From 69291fc6600fd00ecea9892b7a351b83774eb879 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 19 Dec 2023 14:41:55 +0200 Subject: [PATCH 001/132] chore: remove "libs" config --- foundry.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/foundry.toml b/foundry.toml index be5079296..0ec326a6a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,6 @@ bytecode_hash = "none" emv_version = "paris" fs_permissions = [{ access = "read", path = "out-optimized" }] - libs = ["lib"] gas_reports = [ "SablierV2Comptroller", "SablierV2LockupDynamic", From 5e2f91c68f697cd570617b2a232a01716b8ccb57 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 19 Dec 2023 15:10:45 +0200 Subject: [PATCH 002/132] docs: update wording in changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4513f1a16..649d37279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The format is based on [Common Changelog](https://common-changelog.org/). ### Changed -- Upgrade Solidity to `0.8.23` ([#758](https://github.com/sablier-labs/v2-core/pull/758)) +- Use Solidity v0.8.23 ([#758](https://github.com/sablier-labs/v2-core/pull/758)) ## [1.1.1] - 2023-12-16 @@ -35,7 +35,7 @@ The format is based on [Common Changelog](https://common-changelog.org/). - 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)) +- Use Solidity v0.8.21 ([#688](https://github.com/sablier-labs/v2-core/pull/688)) ### Added From c1a7fe555dda2bece15833930f1fed9dae7d4b2f Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 21 Dec 2023 14:31:22 +0200 Subject: [PATCH 003/132] chore: fix SVG generation script closes #764 --- shell/generate-svg.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/generate-svg.sh b/shell/generate-svg.sh index 4f5a0d556..7748644d6 100755 --- a/shell/generate-svg.sh +++ b/shell/generate-svg.sh @@ -5,6 +5,7 @@ # Pre-requisites: # - foundry (https://getfoundry.sh) +# - sd (https://github.com/chmln/sd) # Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca set -euo pipefail @@ -24,11 +25,16 @@ output=$( "$arg_amount" \ "$arg_duration" ) -svg=$(echo "$output" | awk -F "svg: string " '{print $2}' | awk 'NF > 0') + +# Forge adds 'svg: string ' as a prefix before the SVG +# - The awk command records everything after the prefix, while filtering out empty lines +# - `sd \\"` '"'` removes the escape backslashes +# - `sd ^\"|\"$' ''` removes the starting and the ending double quotes +svg=$(echo "$output" | awk -F "svg: string " '/svg: string /{print $2; exit}' | sd '\\"' '"' | sd '^"|"$' '') # Generate the file name name="nft-${arg_progress}-${arg_status}-${arg_amount}-${arg_duration}.svg" -sanitized="$(echo "$name" | sed "s/ //g" )" # remove whitespaces +sanitized="$(echo "$name" | sd ' ' '' )" # remove whitespaces # Put the SVG in a file mkdir -p "out-svg" From 4132a38491b1fa914581cf03329c8d0b8df37f14 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 21 Dec 2023 17:39:49 +0200 Subject: [PATCH 004/132] chore: update gas snapshot --- .gas-snapshot | 518 +++++++++++++++++++++++++------------------------- 1 file changed, 259 insertions(+), 259 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 22f579f78..108269f64 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,9 +1,9 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87632) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78216) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78225) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79430) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87490) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78074) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78083) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79288) 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_StatusCanceled() (gas: 90245) 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) @@ -16,285 +16,285 @@ Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (g 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() (gas: 833032) 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_AllStreamsNotCancelable() (gas: 859296) 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, μ: 1197307, ~: 1201972) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565501) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78511) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 341157) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 945711) +CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1196571, ~: 1201304) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565457) 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_AllStreamsNotCancelable() (gas: 572656) 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, μ: 797110, ~: 798213) -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) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 245358) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 657145) +CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 797212, ~: 798269) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 386086) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 371238) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97103) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 373429) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 371805) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76356) 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: 68085) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87331) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 67976) 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, μ: 453577, ~: 454727) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76907, ~: 76982) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269481) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254609) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 261461) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 452520, ~: 454733) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76862, ~: 76937) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269459) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254587) 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_RecipientReentrancy() (gas: 256767) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 255154) 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, μ: 309387, ~: 310054) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76947, ~: 77022) -ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319728) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 185625) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 309321, ~: 310032) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 77016, ~: 77168) +ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319657) 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_ClaimProtocolRevenues() (gas: 246434) ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18915) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5374061) +Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5375661) Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 4181201) -CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380621) -CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4100448, ~: 3558725) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287592) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286442, ~: 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, μ: 3967005, ~: 3991455) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282990) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289757) +CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380563) +CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4094598, ~: 3552269) +CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287570) +CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286462, ~: 286521) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 370909) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 377697) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 47557) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 58099) +CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3941438, ~: 3983919) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282968) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289735) 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, μ: 371749, ~: 379742) +CreateWithRange_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithRange(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256)),uint256) (runs: 50, μ: 367857, ~: 375714) FlashFee_Integration_Concrete_Test:test_FlashFee() (gas: 50968) FlashFee_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 18626) -FlashFee_Integration_Fuzz_Test:testFuzz_FlashFee(uint256,uint256) (runs: 50, μ: 51839, ~: 52081) -FlashLoanFunction_Integration_Concrete_Test:test_FlashLoan() (gas: 402140) +FlashFee_Integration_Fuzz_Test:testFuzz_FlashFee(uint256,uint256) (runs: 50, μ: 51835, ~: 52081) +FlashLoanFunction_Integration_Concrete_Test:test_FlashLoan() (gas: 394969) FlashLoanFunction_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 21603) -FlashLoanFunction_Integration_Fuzz_Test:testFuzz_FlashLoanFunction(uint256,uint128,bytes) (runs: 50, μ: 403153, ~: 406890) +FlashLoanFunction_Integration_Fuzz_Test:testFuzz_FlashLoanFunction(uint256,uint128,bytes) (runs: 50, μ: 395010, ~: 399680) GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13215) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307759) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307700) 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_GetAsset() (gas: 234445) 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_GetCliffTime() (gas: 234929) 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_GetDepositedAmount() (gas: 310497) 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_GetDepositedAmount() (gas: 237216) 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_GetEndTime() (gas: 310295) 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_GetEndTime() (gas: 237068) 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_GetRange() (gas: 309721) 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_GetRange() (gas: 237286) 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: 72524) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72382) 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: 362867) -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: 399390) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 362699) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 332639) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 337847) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 337861) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 377426) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 399155) 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_GetRefundedAmount_StatusDepleted() (gas: 287732) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 257396) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 262604) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 262618) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 298965) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 320726) 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_GetSegments() (gas: 315199) 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_GetSender() (gas: 307418) 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_GetSender() (gas: 234179) 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_GetStartTime() (gas: 310624) 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_GetStartTime() (gas: 237391) 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() (gas: 278661) 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_GetWithdrawnAmount() (gas: 384601) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 335821) GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387702, ~: 388140) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337638, ~: 337804) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282118) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262600) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387573, ~: 388098) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337524, ~: 337745) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282096) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262578) GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285328, ~: 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) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285296, ~: 285238) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 264308, ~: 264502) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 515747) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 336044) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 327288) 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_IsCancelable() (gas: 372735) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 262953) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 254080) 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: 362513) -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_IsCold_StatusCanceled() (gas: 376124) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 362345) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 330545) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 336315) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 352597) 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_IsCold_StatusCanceled() (gas: 297714) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 287436) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 257360) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 263242) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 263777) IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361951) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326771) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361783) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326712) 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_IsDepleted() (gas: 286836) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 253489) 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() (gas: 327052) 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() (gas: 253851) 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_IsTransferable_Stream() (gas: 327214) 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_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 515746) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 254035) 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: 362027) -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) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 372790) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 375662) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 361859) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 329982) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 335926) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 352082) 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_IsWarm_StatusCanceled() (gas: 297221) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 286912) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 256759) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 262825) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 263224) 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: 16733) -MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 1039753) -MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan() (gas: 178987) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 16961) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16735) +MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 1039755) +MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan() (gas: 175401) MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan_AssetNotFlashLoanable() (gas: 15248) -MaxFlashLoan_Integration_Fuzz_Test:testFuzz_MaxFlashLoan(uint256) (runs: 50, μ: 178984, ~: 179002) +MaxFlashLoan_Integration_Fuzz_Test:testFuzz_MaxFlashLoan(uint256) (runs: 50, μ: 175401, ~: 175418) 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: 320228) +ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 320169) ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10125) -ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246945) +ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246923) ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10111) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361988) -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: 398898) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523491) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361820) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 335782) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 335775) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 342622) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375571) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 398663) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523373) RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11099) RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 45465, ~: 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_RefundableAmountOf_StatusDepleted() (gas: 286869) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 262546) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 262669) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 264156) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297126) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 320250) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 380366) RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11110) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30678, ~: 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) +RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30817, ~: 30858) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 694189) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 687264) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 292481) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 692393) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 687871) 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: 68389) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87318) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68280) 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_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 649669) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 481487) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 474530) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 219327) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 479667) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 475137) 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) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 436859) 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: 62214) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13222) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 624896) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 625096) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 12399) 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: 311750) SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23280) -SetFlashFee_Integration_Fuzz_Test:testFuzz_SetFlashFee(uint256) (runs: 50, μ: 37754, ~: 39448) +SetFlashFee_Integration_Fuzz_Test:testFuzz_SetFlashFee(uint256) (runs: 50, μ: 37712, ~: 39448) SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6551561) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2258131) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2301931) SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6550197) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2256602) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2300372) 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) +SetProtocolFee_Integration_Fuzz_Test:testFuzz_SetProtocolFee(uint256) (runs: 50, μ: 43103, ~: 43074) 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: 362652) -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_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 352719) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 362484) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 336527) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 330626) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 376298) 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) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 263275) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 287551) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 263440) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 257417) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 297871) 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_CurrentMilestone1st() (gas: 45903) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestoneNot1st() (gas: 50746) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 256899) 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: 68723) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68614) 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: 87798) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116445) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3521669, ~: 3127614) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3971180, ~: 4105954) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 276351, ~: 270631) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87731) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116269) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3515843, ~: 3102346) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3963864, ~: 4082808) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 275280, ~: 268771) 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) @@ -304,9 +304,9 @@ StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_St 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, μ: 234550, ~: 235267) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 232550, ~: 232497) 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, μ: 239192, ~: 241446) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 237703, ~: 239647) ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset() (gas: 31848) ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset_FlagNotEnabled() (gas: 41868) TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13542) @@ -315,99 +315,99 @@ 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) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 314151) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 326457) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 240338) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 253182) 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_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 364415) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 327602) 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: 75443) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 289206) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 254379) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75301) WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14165) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 265059) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 158734) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100587) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 140673, ~: 156073) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 265000) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 158508) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100445) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 136366, ~: 155717) WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75583) WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14179) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189290) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189268) WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 111578) WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100775) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 99101, ~: 109924) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 135217) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80287) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117564, ~: 120638) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82928, ~: 83069) +WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 101446, ~: 109924) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 134996) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80178) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117466, ~: 120596) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82778, ~: 82960) 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, μ: 73574, ~: 73703) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83080, ~: 83218) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73894) -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: 83367) -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, μ: 2745706, ~: 2745970) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 73602, ~: 73703) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83094, ~: 83276) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73755) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21033) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124543) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83228) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1830075) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9112) +WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2744527, ~: 2744738) 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() (gas: 1263872) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9165) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1773592, ~: 1773439) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19918) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67854) -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, μ: 121478, ~: 98629) -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, μ: 3965055, ~: 4005165) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160774, ~: 160963) +WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1773301, ~: 1773175) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19930) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67757) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 385016) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112705) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81264) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72522) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 362691) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122619) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 390024) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 363246) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 382203) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 124033, ~: 98708) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145420, ~: 145420) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3963949, ~: 3999433) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160726, ~: 160927) 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() (gas: 268373) 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_RecipientDoesNotImplementHook() (gas: 259672) 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, μ: 99389, ~: 99269) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 273408) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 260227) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 292836) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 99421, ~: 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, μ: 141114, ~: 141030) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 141225, ~: 141111) 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: 363782) -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: 400691) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 335154, ~: 352469) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 298041, ~: 289776) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 378069) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 347594) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 337199) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 363614) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 333948) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 340171) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 378411) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 400456) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 332901, ~: 320879) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 301928, ~: 300161) 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, μ: 463735, ~: 463093) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263728, ~: 263963) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 440141, ~: 440973) \ No newline at end of file +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 253600) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 263471) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 288644) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 258672) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 265025) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 299992) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 322002) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 287022) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 461540, ~: 460821) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263665, ~: 263941) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 437724, ~: 436534) \ No newline at end of file From c1cca898090f76b869a42853cb7d5b4b29d8a679 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 21 Dec 2023 18:01:45 +0200 Subject: [PATCH 005/132] chore: specify number values in @custom field --- src/types/DataTypes.sol | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 48a899c75..8ea369cb0 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -54,17 +54,17 @@ library Lockup { } /// @notice Enum representing the different statuses of a stream. - /// @custom:value PENDING Stream created but not started; assets are in a pending state. - /// @custom:value STREAMING Active stream where assets are currently being streamed. - /// @custom:value SETTLED All assets have been streamed; recipient is due to withdraw them. - /// @custom:value CANCELED Canceled stream; remaining assets await recipient's withdrawal. - /// @custom:value DEPLETED Depleted stream; all assets have been withdrawn and/or refunded. + /// @custom:value0 PENDING Stream created but not started; assets are in a pending state. + /// @custom:value1 STREAMING Active stream where assets are currently being streamed. + /// @custom:value2 SETTLED All assets have been streamed; recipient is due to withdraw them. + /// @custom:value3 CANCELED Canceled stream; remaining assets await recipient's withdrawal. + /// @custom:value4 DEPLETED Depleted stream; all assets have been withdrawn and/or refunded. enum Status { - PENDING, // value 0 - STREAMING, // value 1 - SETTLED, // value 2 - CANCELED, // value 3 - DEPLETED // value 4 + PENDING, + STREAMING, + SETTLED, + CANCELED, + DEPLETED } } From f87dc4f1ff912c4814ab19a894ddd41274cc2fb2 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 28 Dec 2023 12:44:40 +0200 Subject: [PATCH 006/132] build: install deps in prepack --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 968765499..621102a65 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "gas:snapshot:optimized": "pnpm build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", "lint": "pnpm lint:sol && pnpm prettier:check", "lint:sol": "forge fmt --check && pnpm solhint \"{script,src,test}/**/*.sol\"", - "prepack": "bash ./shell/prepare-artifacts.sh", + "prepack": "pnpm install && bash ./shell/prepare-artifacts.sh", "prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"", "prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"", "test": "forge test", From 57a9174edac19421c6633cd9ea9a3b335cb78978 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Sun, 31 Dec 2023 12:36:29 +0200 Subject: [PATCH 007/132] chore: remove stale .gitattributes --- .gitattributes | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index d5e5d2770..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -lib/** linguist-vendored From 78fd5f9bca9bd2ed5833263568241bc211a601d0 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Sun, 31 Dec 2023 13:37:55 +0200 Subject: [PATCH 008/132] chore: remove stale "lib" references --- .prettierignore | 1 - .vscode/settings.json | 4 +--- SECURITY.md | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.prettierignore b/.prettierignore index b3ec58260..1b0ebd756 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,7 +4,6 @@ broadcast cache coverage docs -lib node_modules out out-optimized diff --git a/.vscode/settings.json b/.vscode/settings.json index be6b5a15e..436b490ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,11 +9,9 @@ ".gas-snapshot": "julia" }, "editor.formatOnSave": true, - "npm.exclude": "**/lib/**", "prettier.documentSelectors": ["**/*.svg"], "search.exclude": { - "**/node_modules": true, - "lib": true + "**/node_modules": true }, "solidity.formatter": "forge" } diff --git a/SECURITY.md b/SECURITY.md index 8ae591510..c1a2951ad 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -22,8 +22,8 @@ The scope of the Program is limited to bugs that result in the draining of funds 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. +- External code in `node_modules`, except for code that is explicitly used by a deployed contract located in the + [src](./src) directory. - Contract deployments on test networks, such as Sepolia. - Bugs in third-party contracts or platforms interacting with Sablier V2 Core. - Previously reported or discovered vulnerabilities in contracts built by third parties on Sablier V2 Core. From 35a1acf7a22e8e1b3d2018e167224507bf98232a Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 1 Jan 2024 11:34:04 +0200 Subject: [PATCH 009/132] ci: foundry multibuild workflow --- .github/workflows/multibuild.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/multibuild.yml diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml new file mode 100644 index 000000000..def23b2d1 --- /dev/null +++ b/.github/workflows/multibuild.yml @@ -0,0 +1,25 @@ +name: "Multibuild" + +on: + workflow_dispatch: + schedule: + - cron: "0 3 * * 0" # at 3:00am UTC every Sunday + +jobs: + multibuild: + runs-on: "ubuntu-latest" + steps: + - name: "Check out the repo" + uses: "actions/checkout@v3" + + - name: "Install Bun" + uses: "oven-sh/setup-bun@v1" + + - name: "Install the Node.js dependencies" + run: "bun install" + + - name: "Check that V2 Core can be built with multiple Solidity versions" + uses: "PaulRBerg/foundry-multibuild@v1" + with: + min: "0.8.19" + max: "0.8.23" From 38bdf71434b27747b48c3a1a8af657090622b360 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 1 Jan 2024 11:53:37 +0200 Subject: [PATCH 010/132] build: switch to bun for dep management (#775) * build: update solarray * build: switch to bun for dep management * docs: add more context in contributing guide --- .github/workflows/ci-deep.yml | 32 +- .github/workflows/ci-slither.yml | 32 +- .github/workflows/ci.yml | 43 +- .gitignore | 1 + .prettierignore | 1 + CONTRIBUTING.md | 14 +- README.md | 8 +- bun.lockb | Bin 0 -> 43222 bytes package.json | 12 +- pnpm-lock.yaml | 738 ------------------------------- shell/prepare-artifacts.sh | 4 +- 11 files changed, 49 insertions(+), 836 deletions(-) create mode 100755 bun.lockb delete mode 100644 pnpm-lock.yaml diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index 66f525ad6..a3c69eff9 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -41,22 +41,14 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - - name: "Lint the contracts" - run: "pnpm lint" + - name: "Lint the code" + run: "bun run lint" - name: "Add lint summary" run: | @@ -72,19 +64,11 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - name: "Show the Foundry config" run: "forge config" diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml index d2e2f57d5..f9e8444ba 100644 --- a/.github/workflows/ci-slither.yml +++ b/.github/workflows/ci-slither.yml @@ -19,22 +19,14 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - - name: "Lint the contracts" - run: "pnpm lint" + - name: "Lint the code" + run: "bun run lint" - name: "Add lint summary" run: | @@ -51,19 +43,11 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - name: "Run Slither analysis" uses: "crytic/slither-action@v0.3.0" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c424484e..f75319bba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,22 +26,14 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - - name: "Lint the contracts" - run: "pnpm lint" + - name: "Lint the code" + run: "bun run lint" - name: "Add lint summary" run: | @@ -57,19 +49,11 @@ jobs: - 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 Bun" + uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "pnpm install" + run: "bun install" - name: "Show the Foundry config" run: "forge config" @@ -112,17 +96,6 @@ jobs: - 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: "Restore the cached build and the node modules" uses: "actions/cache/restore@v3" with: diff --git a/.gitignore b/.gitignore index 9d4d1426a..dfe17c873 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ out-svg .pnp.* lcov.info package-lock.json +pnpm-lock.yaml yarn.lock diff --git a/.prettierignore b/.prettierignore index 1b0ebd756..0fba7f6e2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,6 +15,7 @@ out-svg *.sol .DS_Store .pnp.* +bun.lockb lcov.info package-lock.json pnpm-lock.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1f7ea57fc..28a40f2df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ You will need the following software on your machine: - [Git](https://git-scm.com/downloads) - [Foundry](https://github.com/foundry-rs/foundry) - [Node.Js](https://nodejs.org/en/download/) -- [Pnpm](https://pnpm.io/) +- [Bun](https://bun.sh/) In addition, familiarity with [Solidity](https://soliditylang.org/) is requisite. @@ -26,14 +26,21 @@ Clone this repository including submodules: $ git clone --recurse-submodules -j8 git@github.com:sablier-labs/v2-core.git ``` -Then, inside the project's directory, run this to install the Node.js dependencies: +Then, inside the project's directory, run this to install the Node.js dependencies and build the contracts: ```shell -$ pnpm install +$ bun install +$ bun run build ``` Now you can start making changes. +To see a list of all available scripts: + +```shell +$ bun run +``` + ## Pull Requests When making a pull request, ensure that: @@ -48,7 +55,6 @@ When making a pull request, ensure that: - Gas snapshots are provided and demonstrate an improvement (or an acceptable deficit given other improvements). - Reference contracts are modified correspondingly if relevant. - New tests are included for all new features or code paths. -- If making a modification to third-party Node.js dependencies, `pnpm audit` passes. - A descriptive summary of the PR has been provided. ## Environment Variables diff --git a/README.md b/README.md index 44fc6ce53..84c7526ea 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,13 @@ of tokens deposited. This is the recommended approach. -Install Sablier V2 Core as a Node.js package: +Install Sablier V2 Core using your favorite package manager, e.g., with Bun: ```shell -yarn add @sablier/v2-core +bun add @sablier/v2-core ``` -Then, if you are using Foundry, add these to your `remappings.txt` file: +Then, if you are using Foundry, you need to add these to your `remappings.txt` file: ```text @sablier/v2-core/=node_modules/@sablier/v2-core/ @@ -46,6 +46,8 @@ Then, if you are using Foundry, add these to your `remappings.txt` file: ### Git Submodules +This installation method is not recommended, but it is available for those who prefer it. + First, install the submodule using Forge: ```shell diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..240f58ac02d86563e82730c3ce788cc177f815b8 GIT binary patch literal 43222 zcmeIbc|4Tg`#(N3WT~`}q(XZbyDSNbv`A!WK^hE(F{7EG6rxlr6-lYIuhPEJChdFL zR6=QAZ0-B!aaQAxE(EI)V{T`n`IdY)21i_J^TpouNDiB7o#jIEp6?q1OaW1j^`TjoK>7O^nm|N8yTqGzu zbt&|7_LGrS?--_E5=IZ&422+wB@sjEA90fOzPm_zK}D?@j3gk2GQ<-g)`VCj;DvMf zVn(!(BNlTx!VPi^h6<#M*+D!GlvyslKLui8dIH2PAogu0;U5OED&k1<2Qwx4{UOHm zYY?}DSWiL19|Gmn;GP{3OUV=?84E!^Y!6Qm!WM-y7%6by3hu9fN>EN?$i!F}OjXC&4flv2#pQFO z001H?V-uvKyq%=^3UGrsi4Y_I1&FczT!=Lw4uC|sO!9<39Uu-9Nc!RgG#1O}LX7%Oq=vQC?R7#rxjU^av3vjvd8gu!UjKY@vw54dV-h90ntdCkR4? z2>8Kp$6!npvZJHp7>ttuj`BtV81_dI#3&z^AI=eS#Ud_0l*bJV7axFfD9;pWzeGcf z_wHb9$nOj>wpRg^hV6X@_njf;2!#S6i!U?Lbz;rLKHh5)q$XK5WyCUZSfex8y{b*b^e5U(1h;&9aYt=ua4ewWysrAkJs&=UZ&mQ>5z9L7PWFLA3C5{%cRr( z26JZiu@9PU)k-12Py5XNNtWMVl&1FlZts_>taUa+xnjo7JdGibeOoT<{_y3=gy@`G z7q7owvh!xgc)i!k!{QIT-C(t|=s|4%6*lfS{2!01j`f|Qt-gH6p$%};fVzV*&t%b9)i{x!w;`<`xwJ@>5Zsb{9nZ((M><|D`R zq32X*<$}+>U)`+}X}-)K-*#4y?F%QTw45-1V8@4P9}j)aYvW+CK5V6WOJS>7Gxygr z8C%cPj@nMrzd!5x_JdesX;hysL0c9Djrd_P!F_Pvi`LUUl)Fw^IWaGJdF7JV`ggym zY1J56W{A^JLae(7AbPwTeI%d6Fv_#VG|`o+l8=WcU0Mud)< zSKD!nyUW>~PD`^Vu~kmylwR%?ANxf|{=qoU+S=$bM{5;w?$-1k<#}Ux!0U7O+bnyb z+2P)eFpUj{$EzM(xuNhht1mx$dyC0C2c)>$t?@ZJHT&!R0b>KVmmjLu6B%|4w+!59 zY*>>uxlE_^#b8!kzd38m&GbGUt9bq-wcIEx`#pd0G=gvWZ)J z|JyDnf`c#hdLzs%4?oy)blLg&Yj*p5ODOjFot+(>(5tL^>QMD(o9C$Ayr~%d#A9-^ z;XX_A@9xi23m&;)b@j)fiokYC7I}K3*M6SyqkB~gT`kpVJN0`cpXISnAmHI!wv1BSI)Y2tlgbqZE7#y7cz95h-^B zN(`3r!~DS@>Az)^W{`4f(2%~g`WxdT`Gmg^_^p8-?_r6p-+7R7zl#a~d*HVNek@1Q ze#b*kCuPmx!VLHoArtFwYQGTv*>HjNBR_^e!YqQhylm4+4JVLn7&oVUTj$fZrJSvHxHn)8s(- z+k)Z4wxz!QKW+aY;3wlB_5Y{*iNNm;^%HqW+*m_Mxr@N>0sKv^m*5iqPVoFN2>6NY zO|>DyF93ejA4CkC1OBxCw*sRr@Iy2HD3JP}0RMk8e|G}I!TSHx@$U&8I% z)mlmBkN=e43-}%Xi~2Kx-wF6p9;82Q{|jmT$oHS{>%-v-&fhqG5aUnl4*~xFX8*ey z_=if{k9Gg4{l5Tyci{h%xdW=9bcOLCIMi_le(e9IwjKFU*BIsizZ>x5xWP2&jwS`d z-xd}`Xe@kIE@9uKO6YbesTOXwQj^F{FkKs z$lFxgq4R%}%1`PhxL8J3AmvP9!%O-PF`C+kgnu&d5Be|c=Q8j+1OI<2f7|vy_kUA$ zNaPM`yp(chogE}cIN_&uch$MmMkKCz>&NrwrnZCBZw2q+$nz7i zA#6uuf$)ofAL}Rm|EKm}3H-Le-&8pcEvCwNCHtskZmdZCx z8v{SCd*m6O$RaBy?RSRv+c^JVS<(lx_(&e%Uj+RAz>oJ$l^rn%|4ZP<{S&6OrlsS( ztU&mkbr}ptDL;MgWb>lK*+v$O>5gr_3|X>h$v?5ME(|HUlJ5q{`~1E^p{6FmL5y@r z2h&V~BEJlz{%yLF{W~d?OfDLUN&OFjAI46SGn9wtn+o(8^$XQe{oGZOjo)BU^Ii|>Jw3)brMEO4 zW3-Px(pX=bPLEM`BWXU^G!b997E{_R7;h&lHSAIMFm+g^4kGn zd*G~&vfTj?W55{mo$v+%J%*!2#&96ahcgl?&|`T>@sOs=ijm(_S`K4eD@RN3=`ofY zBTbhTW4W=?a`YI}{iNyi82f!Z5azRiFkp=LLDD!FVhr>c+sC0&e~u9^LYj^-_B&sC zPmd8_AWg>@@g@LaKZt=aKL!W`J;wA{AdDvhVZa#qCgTkRdW^X7RH`IKz69w#J;riV zfiOP_2tyL}_vaYflOj#0$H+HBn%-E9#r}>@YHvYl?C~l#AbeOrMY{fRo=uyIz8pw z_XN5)kLC$MMuLldP69K#ZuhgrTgF+gG}9TMHACcE*L?h|^*M}QeuiFy+N=}~%sbTM zib?6?3H+U3?Gh5N-PKdJwR$q7{o~LPa#I#LDQpKIf{Sx22~3_(km)hO%nbowh53W# z^gESx>q%_wJfmZ$p4k+}`oB{>b6t0_%3iBibDrK@Tohc!>C-N!N-pyA?tRPK>jo8+ zCIJw^#krIO=DzFkxpF)D+F2{b-u@Kx=t{QyxTzkg0sA6XMk>?}>#ks*Za3|INUw)a zb}r}K%j9~Pxd-aMNEp}Rdg#^lX__P60T97O8z+HjRi{3uNV5gk&d#T}GTPinCoJky zRuxGe{(KCKbWSs#}9 zd`;et$yQp$j#<73yKCMUT)9cmW@bp>(Q9**s<#v$aNe`e)%y_u5qa_4j0EPE2Oi_R zuXzN$H=H`sbF$qi)eaBNcU;+__p?1CmtSVy*y-Qyf>l4aKC#_J=X6Bh77sD=YJW8G zh4qtf8?JFo2dHQO5Wyw;NyKIrZB2Jk3GOvaY16ipZ9M}zp1s&3vg4*@ZTj|homo4x zI?MgX?X%4{m`#5DeczP%TMksdb|^o&{^mK3$&v0=b9#!t({NP~P#T!UeKtO=D%@$% z)=&4_=9??$1)OOA(W%e5p|OUy!?TP!saZJ}l+}v2cbpiYG-1azE&D$6kC`a*#ylwS zd}iBb+!80iA@bs0jRdA?@7tG7&9iRVrAY31@j%lJ$%5mpb}wKJ*N%^xJZDeUd<~Ta zSM8OnZoQhB|19TjSFcNI%tPV|^Koq>l}kplQ=S13!Nq4X5}2Ed(h}QSJapCQY;R?7 z#pS$8cGSRAA!{yA-+kzAq}S+0ey?*DRD8WxnHKQau%h)MTT>0)Z{x$P509U*e5n45 zla>HPaOv;4nPG?APWW#dJ|%Acx=z+V<~!Y5RN^zm@;& z-7h;VGkIfJ>hLs46v)ipwICuudsAZG5gKkQA}qwrOFI*`c6A&vwrqZnfr9Xe-kz7n zA0EGdL`%<3W6Ebnt4)~Px7;sak^D;W+8YNZR2SzQ@{lU+q(9?y#&^pn}Ui%h08^Eu){FR;|ov zwdDLa_xSs7bnl&ZRbJCW@(dxFf5~$c!ZXFyh2^S?E4J;l-0#};q1FZ~-L%NLUSE=p zzbv1Skzf;hV%?d0m33ymD+f$unO4bL>QeP*&)am%=8aoFx3u^>0cu;zwASCa z@_l%5{-Gr1=jhzou7E>uQ70rYcWLiixTMvGt~J4}hZb(SK3Qkzr3{mP;>>dit|MyY z!|jego9v~PIymLE`GS(#KJMqo+x6l;i<@y`=K_{TLC!IJCLy@^%tivUcK4zStPcbI zb3UB+xM9-Ms9f{b2$vc&ov}Xq*mvy41_aIZUfHGB%2@->#DADu`bN`W>)SnNa`cM> zw;Igt`KbcuFoH`z4`UvgJH?~F_q%Z0TT=~F4h^&Y;CQI6*-qmJi~O9uCpQ1mV#Ngg z;q9Ur3Efs4_@0*0W^78KOYpvTYuumq@pakv`7oZZ5nP-rNMHth>ouk}V^{S9^$Uga ztNiBl&|bDQ;<@qEO|>s;W)y!-cb&PfS(ly^s zFIcK>I;^wj;`yvRt1W_Itrj0z){j+j5P%4-CIN+*IdyXS`xLYH{gYBOkLr{-eehS! zUhSkjqO!&F^A?JVPqaR!f&$>+=C#vb>4tD6F`z8Ls=&L(gtLJ|z+oRa&^RSIct-@Qpaay9?xZOkZPo zB%kAbbjEmBRy7S*n~rOF>FkJ{S(iR}B@|TVhRNG6>(_Ga?#eOGn-7_KQMdh7t9}bw zcRjd%SLeK5dpn<~EAGeAFZvMItk*TowO@w>cbbc98tFH3eu41Jqugd~YNup9ZFkUj zde?_u4y>yeQdK*wTzaFXuH6`ee%y#W|*H~ zL55%`4YxA_N&{2>jo1CjN#<7m#zl5;a;Mwh4ouqjVXe{^%^xiC*JKmW0rPbhoQ!#iu~_N!Zu3i`bedwSa1brp<&llw0$oV{VKmhnzCU9r+4 zC-3B*(d@*j$qpT?qb~2Cc(Pm}D(+a`iNxl+RGN1Z4)zcIy7Qc(8b0F@J?PPKA28xq zZ0ncsRKs^*>T_-DDSJO#JbE-Yqo?uS8?le7pC8I^Q+n;(xf<`422;-IhN$g4bIoYd zyzE=P_xLSXm+xE9*Nd)n+%m%?*YnBg6}Jy+&W?!bGup_zV*jVLMX!sl#Jif5EV66X z`Cuo;^1E9$zdKaC(A)lDM##tWUz)3AZOM&DI(5XHZfD)-xIF@2A5@4vWO*R<E#kH@1#b@7;FS z6q+8o({T;&ztVlOfPM9G4{fIbFVFfc4?OW@m3eWVuYJM0w#_e{J9?Pc+GRr2vxhHq zeYP&=oHW}rxNS*B)!Ys@cB!aE7FpA9d(d&$eS45@7ZtGD=B?J!1Ix~ZmH7z z`wROe+{#cLwJyP<_vPM8d^UCNJijY}ozGZp%uov5H^FttyY{m=!&a}L;r68CdZ@){ zD=bLyG|d-wy~JN`^Tc68OSy#)qxEh2&sI31zm-!kK5zPraVu6h7}sQ9f8xGB?9go& z!SuYhm**9kGM(uA-(GawEe@+*HY;+OP-Q+iGGfDRfuPLBJFD``IVZ0%UoC^Lsywl{ zw57Ca?Pb^PKId9L-JR$+BtvIS-Q4FkS1v0b49Ie!$=jQbTX^m0hnee7pS(Du#$iJK zbJr>}`zmu`wO;P%b9ww}1y?H7!#}@?Xrmxn@aQ=AXvCMESMAKsu3R6aU-%}ox$^tN zG+eYf5}520S6*%Fc5FufD61i@vL2cl9ow#DaFbI#Zl7|YZQ7lXX49O5iqD?n%FT~i z`)XQ0?*t{Sl&wemO;r4r)-!42E<*q!<3gW+Ld<;IY0d7FvGMPCmf0Wc&M)%Zy(;^N zeSZ4DQN6FtEMFQ@FsCNHNPd?~;vAuk^;>iI=ys7q>RovLtMiP=vF%G89*q%vg&}{EpG$ieYs;>bY0^rt;fnIUfww9drcew5k0U7D8$T%ZnIA9@n0gy zyELWrz!-y|)Uo@u+xGNo=fCB(cFy4gXJ;J^+|^>&m5oZLtEPGPE3Im~ZC!_5pY>MB zO~~1KPvs?j{xzcGt}~hTqPfRsc^mPBN^KTS>A2X|bU17pn zFB+~10!jmO)Y6g@UPZRe&z2up8PPxGblB>e51Zzzdr$Ar>ECP51&{41@3oUv{haK( zab7W6pBrmjRlD)R{rRhRFR<0VZpd2-I7D7k0tzwn>Nb}L<34=L7-N&GyrSi)LZ{fz z%*+A2A3K6l9z7ix?EK1}&#vU^XK+@T&%a(hMLVa;zlW#7{TEK7jJDUbJpY-7i|6np zFvnIWu{zweGu@W|)x2lV75&mRgX{FdF6sF$IcVN{$F%(!ZTO!`60Y&p1=%+$Hehhrv7zt#CEs{m z{Ip7EcVCO{xCRq>@mY=pCO7KSxlCJyqaRl<9kb#@^V>T&hh7^syp!{=adqt`g%8p< z@#41cymn}N=j2w=S3jLQ(yPv6MqEa_t~y7D2G6~<4xhCNF23I&fm!UfxLd74tAj7& zjJ1~CWiH65=*cy^wQ6o@?c!+(-&3~-`t|)hV&Z*^vHL%s$#gkld;jv{9n+^C|JLjh z^P!dLCEP<2Tzp?b0`s!t^~d8C9;h!|GuSM#Rg`*~=#^OI3*YyfS;<;6FO$_{PgPxD zY7aZDvbsPu%TY(ohyP7u^qC1GX7(!c;q^_R+ZoP5Brp$na`iiWGSi<!E{I$`~Y zFDd;!hTk_n$eiu>W}~r5pSlyr9@Q?3dDGJU(<*(9V+&vIQGM}Z_PZRPIfFEr4_5&Y zk=KTRLd=}9u&qwH8+&-O%X`1i57aNSI-<5|vEm*3ZbkDp)Ma&hu)o)3TFEVid@Nu{3~;ogS?=KXzf z3U6bVZMx#Nv~bk&5&ds{4_&?{b?)^7M%?ssowkXVZm{?l#%*jWNJThD0dn*2peaH#Vb@`Ren!UT-<@CBGmvTDX zP%N$9Y(K1Wq{jCgGqcJ5_w_={c8NZ`9Z=paH*VkDz8Z6~0|1EN_9vhaGjB#|>-zZD zJn%jL;m9!Oumc@BIjxx*aMxqkAV%Zq|j$Vz)bk0+q(=RXMIn zj_=XS>h889jx=0*I_~GS!ZT?>`uh(rT~>a)!$s#)dTN=TB|2Spelpif8}(srP~5Tb zlM1H}Ih@|m`TOMWYVCZMWlzejyQp#PL(l%I+&45_2RiP@Pw9aJAIMF=80XuiEb&5j zMPuvJ?Qiza(^=f6U-x`LQl|IvjrWr84SKz!nXP#zrs7qbGnOSf!KKIJ+%n{ge~4(f zj&$4yWi|U=jMDZQJ3iv->;pFKb=C5Wv~E*!3bt7J&kXSRG55^T%2|;Uv#QN%X}EaiMFR79&X_&d z!%r=q-KOgxy+yBE49eaZpwLIxUR`HwPs5ejo86APc}(AS|9=0WJrxwYEP7#Q?kVJE z8$B}^WX4e}+2IU8MBae}6k_I^I^WzUWtz65-abkkvweQq&8=NiyEtDg?|4PY@{U`l z_@wCpI@cF3)bQ|&9y)XCn_DM5yUDHEQuh9&V#^bSFV0ucaIp>&nA7t^H=Y%KW_($u zV`ptV{Fq**{w%A^u006veK730dA}us8&i8dEk51);KVP0 zLFC0VBodfQQgXjq@FvgsR#cdBB%sj!QLn0rZs{LOzn@PSH(1YYP|4fe5ySkwcde+c zd)>NUn(4k{1MU~}aeV9VDwaP|U5xKg2`;XoBrq3k)%f9CwVuCGVSwwt!b>9~9hp7f zk69eLoYyk7(k4amtIw5%m7Od0p4xrnyvFP^CUSz~*3QBHhr}1Zi2?@3z5pPCi*pbO z%yH35N7TBQKbL>LLG{d5BPT;R8l_H*KNGz+j0AEx^?CkbyD9@*=IoM z*o%cr=dU&PYd%6FMcr^)3jiXx_zX@0^KQyYkD7L-;|`@%I4<2+ZIHGs*S%)G-eZCK zz>pWNS2i5^*lWrCy^h=j#wu-be&@99i@1Kwjt=rY^z@Wx%&@^Zf#41!pb#@NzntbK zIt2OV``M+byuD%*+eLTE3+ueF&6@m6rq3@g(z>YHz4zHMw|AuEbXaI!etPIMg-Pc} z8MH5mnYC0;W#us%uG>$z6{+8j*yW`ew?Ct)bm&FmvE$oqPu2BavP(79_nmX~y}o`^ zmu<DMKH3vRY+dtky z5NIC8>ZaEsv7Ne)vQDW}dgvT?&bYI~_t0=h&~YDJ zO)^{lYNK1r${+i(w!ZydnCFyWuH1RaR<}_nALayq*qk-w`o;<~Wo^ZgH(t&Pv^{R9 z*+1ED>?NQ6w+gQIcw=64l!og`$BopTQz&?zqPNR-P@BQs?C$8k6y9@aJNsH&#==v) zfwdnFrcKh_Ic8EqmIw3g@MIO0Igh8Vx$Ux*cO@W4d-lu2I42N!N78ZY`UtbCvtHpZQ>>rFkIe!x+6Xn!Mh0+?uPdeIr(C=&?%Ec`5~)x8^>r zSdqKnX~p{?sn1o~pIGpt#nH9Vj)5YVew)+R?%r~J=lX{yW?j-`<@#OUGW5#V2Q*wC zI&N`)+hG^P>uj6(A1geNzrV_Anp;VE@9F14vJa+>9{I#ANKejc~+3ysn5cZp$ZO){Y=W^RbzK7-2UJ` zcjAQi2dlUN`&@n)~!?`&^;i9iwfz{u*qL(E){h8MB6Vc%*zZRlV(tcZZf14WA%% zR)4T$;Q<=%XgaQwW$>|*v-$JvOj46J_xQNRX>0QEl+AK`_5?p)$nQ8{=ELProJYI1 zzu)VWrR~Rp6JwTc>vCb%r^WJB>76?UI=5Iy!yQA%-MKdK*3&MI9X}2}XY3R`(4t@9 zeaq**8iOKkZNGLe=GB3TSH_gJ;}#sgcI%VR%5QgqvyRR>D3^VSUprvJx0j-m!8F{l zblf9*!?$*E@l@E6wQaK3$*EfuXLReie>3l8t39F0%d_?OR}2}b_-x)7rI0pppW66p z&reUzT2Xs!VB)|bpDnk%j=-~eGA{h+xIX>0y5(xQ+_?WLZT1OqTGZ^LhaN^G7MZrq znt$cPx7|A&rrd3Rrd_Vx)&z~tE=zQ`*?3&CQ9Hb{G(xjOhUmqo%`{wpI_`j%>ih2P z(73|VXfFR!cQ^bZ37a=^v(lW>lhdnAj=iiX-*`+;{_TWK<(E6Qn)yxdOpl~?Z;I~} zzcy+yUUg@QUq>1)?uAKU)`eZ0Jjv|@yVTUub&_uX-hFag&wMksyJ6bByDzj%r-3jY6L5p_{ zE&K==M8AP_T$gL!iKCbmr_A-c={u>)A99~zU*|2J=6*FloA=SxYPM}ew(|a7<*N<6 z-sPLxE|%M${yx2%?U2Kjl|8rb5)}8L;f|-{22Wr5#efrWBc8F~aGxdT3kvyLw@k^c z-ut?J{*9yB<(;||rT6ZUn^|n|s=v-BwFm3P=`-zje1Fw%eJ8Eaw+4)QOT%T;agRLd zFhj9W&0EgErf$Z7SAsKlPLF*#GM+cdL|cBPP4#dS!`qun_bk+(bh}l%Zl6+<^0rOb zdTfo;h@gNmHk#J0&1ty!Y)=An!_kXDoa(*GX1m%(Ymx&Pz6G zHp=CN-18q*m7#g^9Tw*vHEvmE|UO1QcSXLs78&sXC5vmae7JtjKt+g0sXpSy5~dP(Z$Bl%B?Lgyvg z=jpf|{KR`=@Y-Uae|{I+Q}S0T*4MT>WXJ^!VhfE_II5+jD0B#*1H7 zdRNXon3Cb}a$TEplgt6`9euR(a)%yFo6a#GvykU1Ue0}*8j!Hy+{pZ4H4}e&PZmnY zU7cH&;-8^6+515C*VJ}B&kibBQSedsk=a2_hZDvj!AEa;e=yOl^J%vIuzg*d^xE%N z_@4*wb)RC`UuBU+)#!q3n!I6j+%4%zN3;@lm(B0;Vb1QvGb@gJ7Je7sT-z~v>y<@y z-;G=Nf2h$flYf0Q>0aSIi?8NS?<||Ics!t$zOH{r!pEwYxR)k+2&dz=>!Up4t);%j zP2nAGQj%^$x4nBe@HvC;C!K#+J2dlPaF1ur>&l(lWAq^3@oia zGE(Pk?2^_Sy{3!n9<{!irWe`lnlSWXwPwY@VfYS<;6@Noh?xs}T;IJoBk0pv`2yyL z!=Knbf!~Ts92t=n8&A1(+1T#z%AI?+tSR@c-Eq~sSIj&-R(uV+5R%k# z?L``HBpr9b#1bRb>+4n=iipoXn>lm%G(YXCrz;eV+YLFejN7TitZ-H9J{uk9noN7k zUD=uM z#adi^;?n26bLaEEsWA?{Iz6fq4A_2p`S;+iomGQAG*kO>*~a-pKCbOV4^ed7#hO!# z0_SGlYaW_%e7{d*_>{m|S-0nyb&K#R&pgy|WZAM6x~~l{hILV2(%LLSr}dX*C*#$I zO#Tm$~P%SN!n0`$GL*es3GAf-XzoX9szs z&e3qAX}JH3OQK(VMkIlG$N2E#;}=F8C~EDH^wxN(k#UD*i#B;&o2j4nX!40zr>Nq) z-Hg}nE81y4>|B302J7y*QTKyIwTHEglPlh>aC@`{fC#RTfc}qSf{SM|BrqL@d6^YW z4rtka(>7;z$+_{Pc{ZNALqD`?|K$CJ^7Yq_C2A$r?z-SvZFjO;)ny0gRHLXzIb)dJ znd_#=om5;FKtCHGn12$>Lt*keoCsr{uS1OWR3))Aj$Bgny;^tAW27 z`2Sl2u*LZs{%YW_2L5W`uLk~V;I9V$YT&O1{%YW_2L5W`uLk~V;I9V$YT&O1{%YW_ z2L5W`uLk}H8unfM(ge)EXmC*rrIra;C(dO)3l zx&Yz#IYvOefu;gY2ATqdeUE*OeT#h=0>lQwe`9D4WC3IXWC+v~s25OIpgutHKxhZp z-$6i5Km&oCfn0#F?_Gfg0}TNh3N#GJ4X7VbUm)zCI3WC{1;4lT1o8s%2J!*&1#$-( z0b~b+--p=)SpiuC*#OxBjRqP3Uku|3!>)D!9pb%%Y0vTFl%07AP$ z`%(Zxe6*c5KxkWNYnYFArwW92hxe_3(C+YF4X8B`+E;rZw6}IZ>OjQS&^EAddjO%0 zV7&of3={+u0)+Yv0}2O1y+#4?fKaajAf-6?17Xfg zNvvY$XVy0$#u_H)zV-8p>Cclh_7U`F67h4|TF%1A#Ap(vVlQD1@wliYXJXVBevwsT zGnhksGAb!yPXQ&7FQkZfR3*7_W=7UVpj6^#mH2Z+G!r9JGaD)gJ+Tsxk4j3YZ?J)S zU&zGgDxjfo(5-0gpn)Xfl~o?3wlTuK{bzeH$Arou9$<;5NqM<(AV6P$BR*q^Z%WAN z3!=f#xDv0j#Cs*=SQwd_0uS*!OZ;0>Xn+SjCiRd@JYq_CPz2)3miWws98=VS34?g$ zCEhd`3`{(bN_oJbiSJs;0KqKCvi5FT54PWz4~ zCZ2Su9Ba(kAV?Mro`Sr2fyf3)F_}4kJrSrE}&T$S)gphXEyQ8 zOXX1ZM!akjZ@yHHnGw`O{Bi%gJ;Xyd@dOM!mJ$hwk8a`%7;>b&O}uy$Z^4jbF6o8e z*F!um6VI-cY?Rc*_xD4ok739Gt)bq2Uk~vQPW%u{c|dQ(V>t0lEH9U6YGjI5MSOx2 z-@}yDkjG#UFU-W-E9Ai7K?#UoapJ#NS`YLB@jy;I9YYTE4)zc6NlttpQ#?2r>%EW@ zZ^w{>Rs}i4FFEmlOrcRZ#3MQJd<;2YZOB7>hZ7&gkOQ*;W)W}X#OpESNc)udH7EX) zAxA2~FUNwpkyXR@fyCFcyc`Z~T!D!9bK+$g&~Wkv*@%C1;)j{)1+WoV4Wu5_iKk|i zS~5zAk9Fe98Fh7lcq9#F5I^d~Uo(Y9X@_`RC!U?D914y2W+y(Nr97sl z4C1Ywc!j2ebSIvpQEHrCtQo}jJMl3MInq8Q-r0m55b;e8Lcac2-O;}jY->L&`>(b2H)BYwwW4v~N{B4Nu7yYM99fgE_G?J0sB z=>MtAqRCp{GUUP zw6{k|c~=(O1*oomx@r!laT!MBE(7+Uuh|hLP0uyK`qXKfU=ZJTA$bm6}QiroetWX|1jQD$p z97xBUU##e+pft#tIe) zIgZi7Amb>uIGnl=b421Wt~fj<$Tn0E!w(V0v4kSyP=PRv!xD)@x=FlT)Za^sN+DT1 zc96)JIOOOi^~m8Ui01GobE2a;JTBijSilzx*}-B_xL6!5vNbjqa>BSGu`tev9~~7T zGJ=|n>qRnVQIfH+%gl_#VUuMs{kj@}sIL-m;8_uIr2ohV{%M8`L}?*FkX})8m>|C+ zq;NyH;y4zyJ_wB^5nCk21P)&;3Km2~vH2k!VX#0H#RU;UxnZH0AHofV;fi`@#d3rq zu7DrSixI-P>10R}a-&&nzKAR4OcJxG=b|7kpG6*aWQ$8mfxP6BMLmNzqPT{-fV1I- zMLlUX#tXK@K{kw8ec_4U6gebMjz(f(3_lo~%HsxesCHos`C+Vy+z@fNEX~&|0+nBX z0~NrEjTNAdSYSDvNit9x3IR&P4U1Y@8)+C_P^k<=Zm^C_qY8q@rZkkAdM7v{A8>B|K8#)TxT;FRAc28+hB#z^8 zL}1HcwT*WItr&pPxxhMMR&7KiT8+q#{Vu5=ghGWtHv|iKu-3y6gYhIw<3E)Hu%GTJ zVJO>@B=gx(92vdWP^caVIas)kS~Sw6e~bamwtF{B&uacqD8n?rLs1~69kpjaLcbL#= zFl8G{S8v(t3-zxU0ZCGrWd#nTDBIx)V_3m#=rn2Sq65~cO1tDxvIMha+AvR(SKQEEU{nMHW%98e3G&?ww4Z9QUSy}Sa zieVFIw>W?#)=BmvEOv}IoFx`Sa`^R0F+!dUczQ8_r{6ZLTC(_qkt-NX5tnQ*q7Z5n z!{(14f}=E=Y9CB;QBkx5~F$SVAxnwb#TNJ1;R+9U^Xk1%i~CjvEX3}P6K|w1Ev>)O6j+tQ239U zXrhGzv4F*c?XwK1hC%?;a6|QCV=L7!n}ACAxlw>6-JgfS)}8|!Ay%j?6Qz{`Fxnl= z4S3MkNPquM;q{85_X4G^#t`A$7X=ZBS@`ltG8Z_CxbXPH5ebChF(TNLIf^Dnv4z2t z*^$PmZI+lD1)F=ErK!CyPaueliEg;ZbqhB1A<*MdupJkPz$`@30=|d?4^L675Vn}j z;_z{&2#;1`T!}gCC?N#dQ1Lpc`m|mpo2uk^zXWNF(2G)j~CM^>GvK)Z;R~jg#@h#{t z%o4DEk=n4Mh~mOyY`qc7XyMNV0ruwvYM<2Dfc)1u0+@fLv8dB}Q)&`(6vst#M3Rw7 z6=cDt3XWd5!PG<~*-ka2@nH;7kK8QT%lc2{K!%_0o3#7+x$*zj26Yh!on+#aA&rb)`aLY3u*u#4 zG+2gY76z<;CN=CAWr_EzDV_*M&G!vw2O%6#JZuqh1HtD6%UXf|Sricenbf4c*gsb! zz=5Lza5^j5A>m_(^x$3gL6Ni&uuHF~zH4kql6N7%MlPEqwd9)wlodVgl{we10$HyahS}g~e zOuZbyR)0+`1AVc!AlwbXONeMZwvhRB@{f`L_m7kYRR^(oxDg0p!I`a01^iqPA%Eg* zQUl2=E8r%Vlq8LfNG@OU5{%-LTvGK>YLTH(S|0-|?T+GZtPAVUSCN;TwF0N~oJdB! zv_o3prQLz~nZp2s&g4c#3xr}gH{poFsncHSi43igg=-JB{shB=nyi_izBE))e+{Fr z@#BYv8Yxyd$dNn{QZLU?JjWn*5Qhh%!_i}?5RRg#xn9D?iRJKFK^!r>NnlYg#^7j= z&k@0iYzRzWyqGAytlj#*%7O&{N&_w9+b!8cOr}VHDl;GKuJJP@^4br;$R*YP)PovK zmTdgqj4P5gZ_r8s3hjb$Hx`iAEF?jaDkcZiNSz-)}>IE(qX1C%_zrr{uD`le}94ZgSbA zJ^il)2aI1OQ^TIpmyEX14ut`Rb_denW>|JBBqzDBisR`q@c(oV_1l2iH3b2Wf9u)n z&w?A{mD)?a83024wZvK^+gr)#4(ITqVGPH@))gKg;n15K0;fUTP9^3A(rH}sf{hg=2#KK{g{dbuJkFM3 zBIJ1wivckGwn^>(sZId+>7FuD%FKe{pGV-!J6WAjUj|_6uc38#hSHdwNna@6U0%1gx|>n1UN` ztK@|{GV;Ydp#{_kr)7=J0u66dBp(1{S5R9BYE6QF_k!;?B~vXoG){)5CFOs9=K`|) zDj8aXJt4c(e=h`}{yr0yiN+1;H*c{47_<+sia%gG?{|D9Q?=6.9.0'} - dependencies: - '@babel/highlight': 7.22.5 - dev: true - - /@babel/helper-validator-identifier@7.22.5: - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/highlight@7.22.5: - resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.5 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@openzeppelin/contracts@4.9.2: - resolution: {integrity: sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==} - dev: false - - /@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: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /antlr4@4.13.0: - resolution: {integrity: sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew==} - engines: {node: '>=16'} - dev: true - - /antlr4ts@0.5.0-alpha.4: - resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /ast-parents@0.0.1: - resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} - dev: true - - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - 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'} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - 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'} - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - 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 - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true - - /fast-json-stable-stringify@2.1.0: - 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'} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - 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'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - 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'} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - 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 - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - 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 - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-schema-traverse@1.0.0: - 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 - - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true - - /lodash@4.17.21: - 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'} - dependencies: - 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'} - dependencies: - callsites: 3.1.0 - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.22.5 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: true - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true - - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - 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 - - /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: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - - /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 - ajv: 6.12.6 - antlr4: 4.13.0 - ast-parents: 0.0.1 - chalk: 4.1.2 - commander: 10.0.1 - cosmiconfig: 8.2.0 - fast-diff: 1.3.0 - 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: 7.5.4 - strip-ansi: 6.0.1 - table: 6.8.1 - text-table: 0.2.0 - optionalDependencies: - prettier: 2.8.8 - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - 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'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} - dependencies: - ajv: 8.12.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.0 - dev: true - - /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/0625e7e: - resolution: {tarball: https://codeload.github.com/evmcheb/solarray/tar.gz/0625e7e} - name: solarray#0625e7e - 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/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index 06ab4fe97..22b5892e9 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -2,7 +2,7 @@ # Pre-requisites: # - foundry (https://getfoundry.sh) -# - pnpm (https://pnpm.io) +# - bun (https://bun.sh) # Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca set -euo pipefail @@ -50,4 +50,4 @@ libraries=./artifacts/libraries cp out-optimized/Errors.sol/Errors.json $libraries # Format the artifacts with Prettier -pnpm prettier --write ./artifacts +bun prettier --write ./artifacts From bf16a469b37b07507f6abb772aae3078abd6ac61 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 1 Jan 2024 12:56:56 +0200 Subject: [PATCH 011/132] ci: define "--skip-test" input --- .github/workflows/multibuild.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index def23b2d1..4c24697a6 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -23,3 +23,4 @@ jobs: with: min: "0.8.19" max: "0.8.23" + skip-test: "true" From 86a92f160df2ddf7722a83cdd9e5049c41645c32 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 3 Jan 2024 15:07:19 +0200 Subject: [PATCH 012/132] ci: bot for closing stale issues and PR --- .github/workflows/stale.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..fcab5f83e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,26 @@ +name: "Close stale issues and PRs" + +on: + workflow_dispatch: + schedule: + - cron: "0 3 * * 0" # at 3:00am UTC every Sunday + +jobs: + stale: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/stale@v9" + with: + close-issue-message: "This issue was closed because it has been stalled for 14 days with no activity." + close-issue-reason: "not_planned" + close-pr-message: "This PR was closed because it has been stalled for 7 days with no activity." + days-before-issue-close: 14 + days-before-issue-stale: 182 + days-before-pr-close: 7 + days-before-pr-stale: 90 + exempt-issue-labels: "help,priority0" + operations-per-run: 1000 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open 6 months with no activity. Leave a comment or remove the \"stale\" label, otherwise this will be closed in 14 days." + stale-pr-label: "stale" + stale-pr-message: "This PR is stale because it has been open 3 months with no activity. Leave a comment or remove the \"stale\" label, otherwise this will be closed in 7 days." From a2fe652380b6eadbff17e9791a75c12cbc2e6531 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 3 Jan 2024 15:29:44 +0200 Subject: [PATCH 013/132] ci: update formatting --- .github/workflows/stale.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index fcab5f83e..398801ecd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -21,6 +21,10 @@ jobs: exempt-issue-labels: "help,priority0" operations-per-run: 1000 stale-issue-label: "stale" - stale-issue-message: "This issue is stale because it has been open 6 months with no activity. Leave a comment or remove the \"stale\" label, otherwise this will be closed in 14 days." + stale-issue-message: + 'This issue is stale because it has been open 6 months with no activity. Leave a comment or remove the + "stale" label, otherwise this will be closed in 14 days.' stale-pr-label: "stale" - stale-pr-message: "This PR is stale because it has been open 3 months with no activity. Leave a comment or remove the \"stale\" label, otherwise this will be closed in 7 days." + stale-pr-message: + 'This PR is stale because it has been open 3 months with no activity. Leave a comment or remove the "stale" + label, otherwise this will be closed in 7 days.' From b66948c9bfff2d096eaa720264361737fe2510d0 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 9 Jan 2024 14:48:48 +0200 Subject: [PATCH 014/132] ci: use v4 of actions/checkout --- .github/workflows/ci-deep.yml | 12 ++++++------ .github/workflows/ci-slither.yml | 4 ++-- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/deploy-comptroller.yml | 2 +- .github/workflows/deploy-core.yml | 2 +- .github/workflows/deploy-lockup-dynamic.yml | 2 +- .github/workflows/deploy-lockup-linear.yml | 2 +- .github/workflows/deploy-nft-descriptor.yml | 2 +- .github/workflows/generate-svg.yml | 2 +- .github/workflows/multibuild.yml | 2 +- .github/workflows/run-smtchecker.yml | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index a3c69eff9..69fb185e2 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -36,7 +36,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -59,7 +59,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -101,7 +101,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -132,7 +132,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -164,7 +164,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -195,7 +195,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml index f9e8444ba..42b17e74c 100644 --- a/.github/workflows/ci-slither.yml +++ b/.github/workflows/ci-slither.yml @@ -14,7 +14,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -41,7 +41,7 @@ jobs: security-events: "write" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Bun" uses: "oven-sh/setup-bun@v1" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f75319bba..ed0899f43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -44,7 +44,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -91,7 +91,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -122,7 +122,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -151,7 +151,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -180,7 +180,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -211,7 +211,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" @@ -244,7 +244,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml index 03eff8a05..d6b14b3cb 100644 --- a/.github/workflows/deploy-comptroller.yml +++ b/.github/workflows/deploy-comptroller.yml @@ -29,7 +29,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml index 24159ddd5..40b942d63 100644 --- a/.github/workflows/deploy-core.yml +++ b/.github/workflows/deploy-core.yml @@ -33,7 +33,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml index f2d7c72a5..b3b5d518a 100644 --- a/.github/workflows/deploy-lockup-dynamic.yml +++ b/.github/workflows/deploy-lockup-dynamic.yml @@ -39,7 +39,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml index 9d51e5855..2a0223e57 100644 --- a/.github/workflows/deploy-lockup-linear.yml +++ b/.github/workflows/deploy-lockup-linear.yml @@ -35,7 +35,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml index ef5ee19f4..c917950df 100644 --- a/.github/workflows/deploy-nft-descriptor.yml +++ b/.github/workflows/deploy-nft-descriptor.yml @@ -25,7 +25,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" diff --git a/.github/workflows/generate-svg.yml b/.github/workflows/generate-svg.yml index f97355082..1050b9992 100644 --- a/.github/workflows/generate-svg.yml +++ b/.github/workflows/generate-svg.yml @@ -21,7 +21,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" token: ${{ secrets.CI_TOKEN }} diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index 4c24697a6..6ee1581bb 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -10,7 +10,7 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Install Bun" uses: "oven-sh/setup-bun@v1" diff --git a/.github/workflows/run-smtchecker.yml b/.github/workflows/run-smtchecker.yml index a6aaa12bb..69c91e6f7 100644 --- a/.github/workflows/run-smtchecker.yml +++ b/.github/workflows/run-smtchecker.yml @@ -7,7 +7,7 @@ jobs: runs-on: "macos-latest" steps: - name: "Check out the repo" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" with: submodules: "recursive" From f7a0c3f7e1a0fcde0a9eb98132b6298c8927ecae Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 10 Jan 2024 09:42:09 +0200 Subject: [PATCH 015/132] chore: remove etherscan API keys (#786) As realized in https://github.com/sablier-labs/v2-core/pull/748, keeping the Etherscan API keys in version control is not worth the maintenance cost. --- .env.example | 7 ------- .github/workflows/ci-deep.yml | 1 - .github/workflows/ci-slither.yml | 1 - .github/workflows/ci.yml | 1 - .github/workflows/deploy-comptroller.yml | 7 ------- .github/workflows/deploy-core.yml | 7 ------- .github/workflows/deploy-lockup-dynamic.yml | 7 ------- .github/workflows/deploy-lockup-linear.yml | 7 ------- .github/workflows/deploy-nft-descriptor.yml | 7 ------- CONTRIBUTING.md | 1 - foundry.toml | 10 ---------- 11 files changed, 56 deletions(-) diff --git a/.env.example b/.env.example index 8e4a32221..0b5c47463 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,4 @@ -export API_KEY_ARBISCAN="YOUR_API_KEY_ARBISCAN" -export API_KEY_BSCSCAN="YOUR_API_KEY_BSCSCAN" -export API_KEY_ETHERSCAN="YOUR_API_KEY_ETHERSCAN" -export API_KEY_GNOSISSCAN="YOUR_API_KEY_GNOSISSCAN" export API_KEY_INFURA="YOUR_API_KEY_INFURA" -export API_KEY_OPTIMISTIC_ETHERSCAN="YOUR_API_KEY_OPTIMISTIC_ETHERSCAN" -export API_KEY_POLYGONSCAN="YOUR_API_KEY_POLYGONSCAN" -export API_KEY_SNOWTRACE="YOUR_API_KEY_SNOWTRACE" export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET" export FOUNDRY_PROFILE="lite" export MNEMONIC="YOUR_MNEMONIC" diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index 69fb185e2..a7fe3e092 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -1,7 +1,6 @@ name: "CI Deep" env: - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml index 42b17e74c..a2501b998 100644 --- a/.github/workflows/ci-slither.yml +++ b/.github/workflows/ci-slither.yml @@ -1,7 +1,6 @@ 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 }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed0899f43..cc40dac28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ concurrency: group: ${{github.workflow}}-${{github.ref}} env: - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml index d6b14b3cb..f045c1346 100644 --- a/.github/workflows/deploy-comptroller.yml +++ b/.github/workflows/deploy-comptroller.yml @@ -1,14 +1,7 @@ name: "Deploy Comptroller" env: - API_KEY_ARBISCAN: ${{ secrets.API_KEY_ARBISCAN }} - API_KEY_BSCSCAN: ${{ secrets.API_KEY_BSCSCAN }} - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} - API_KEY_GNOSISSCAN: ${{ secrets.API_KEY_GNOSISSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - API_KEY_OPTIMISTIC_ETHERSCAN: ${{ secrets.API_KEY_OPTIMISTIC_ETHERSCAN }} - API_KEY_POLYGONSCAN: ${{ secrets.API_KEY_POLYGONSCAN }} - API_KEY_SNOWTRACE: ${{ secrets.API_KEY_SNOWTRACE }} FOUNDRY_PROFILE: "optimized" MNEMONIC: ${{ secrets.MNEMONIC }} diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml index 40b942d63..031572599 100644 --- a/.github/workflows/deploy-core.yml +++ b/.github/workflows/deploy-core.yml @@ -1,14 +1,7 @@ name: "Deploy Core" env: - API_KEY_ARBISCAN: ${{ secrets.API_KEY_ARBISCAN }} - API_KEY_BSCSCAN: ${{ secrets.API_KEY_BSCSCAN }} - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} - API_KEY_GNOSISSCAN: ${{ secrets.API_KEY_GNOSISSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - API_KEY_OPTIMISTIC_ETHERSCAN: ${{ secrets.API_KEY_OPTIMISTIC_ETHERSCAN }} - API_KEY_POLYGONSCAN: ${{ secrets.API_KEY_POLYGONSCAN }} - API_KEY_SNOWTRACE: ${{ secrets.API_KEY_SNOWTRACE }} FOUNDRY_PROFILE: "optimized" MNEMONIC: ${{ secrets.MNEMONIC }} diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml index b3b5d518a..7af3c6955 100644 --- a/.github/workflows/deploy-lockup-dynamic.yml +++ b/.github/workflows/deploy-lockup-dynamic.yml @@ -1,14 +1,7 @@ name: "Deploy Lockup Dynamic" env: - API_KEY_ARBISCAN: ${{ secrets.API_KEY_ARBISCAN }} - API_KEY_BSCSCAN: ${{ secrets.API_KEY_BSCSCAN }} - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} - API_KEY_GNOSISSCAN: ${{ secrets.API_KEY_GNOSISSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - API_KEY_OPTIMISTIC_ETHERSCAN: ${{ secrets.API_KEY_OPTIMISTIC_ETHERSCAN }} - API_KEY_POLYGONSCAN: ${{ secrets.API_KEY_POLYGONSCAN }} - API_KEY_SNOWTRACE: ${{ secrets.API_KEY_SNOWTRACE }} FOUNDRY_PROFILE: "optimized" MNEMONIC: ${{ secrets.MNEMONIC }} diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml index 2a0223e57..b75226c91 100644 --- a/.github/workflows/deploy-lockup-linear.yml +++ b/.github/workflows/deploy-lockup-linear.yml @@ -1,14 +1,7 @@ name: "Deploy Lockup Linear" env: - API_KEY_ARBISCAN: ${{ secrets.API_KEY_ARBISCAN }} - API_KEY_BSCSCAN: ${{ secrets.API_KEY_BSCSCAN }} - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} - API_KEY_GNOSISSCAN: ${{ secrets.API_KEY_GNOSISSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - API_KEY_OPTIMISTIC_ETHERSCAN: ${{ secrets.API_KEY_OPTIMISTIC_ETHERSCAN }} - API_KEY_POLYGONSCAN: ${{ secrets.API_KEY_POLYGONSCAN }} - API_KEY_SNOWTRACE: ${{ secrets.API_KEY_SNOWTRACE }} FOUNDRY_PROFILE: "optimized" MNEMONIC: ${{ secrets.MNEMONIC }} diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml index c917950df..0f880ef41 100644 --- a/.github/workflows/deploy-nft-descriptor.yml +++ b/.github/workflows/deploy-nft-descriptor.yml @@ -1,14 +1,7 @@ name: "Deploy NFT Descriptor" env: - API_KEY_ARBISCAN: ${{ secrets.API_KEY_ARBISCAN }} - API_KEY_BSCSCAN: ${{ secrets.API_KEY_BSCSCAN }} - API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }} - API_KEY_GNOSISSCAN: ${{ secrets.API_KEY_GNOSISSCAN }} API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - API_KEY_OPTIMISTIC_ETHERSCAN: ${{ secrets.API_KEY_OPTIMISTIC_ETHERSCAN }} - API_KEY_POLYGONSCAN: ${{ secrets.API_KEY_POLYGONSCAN }} - API_KEY_SNOWTRACE: ${{ secrets.API_KEY_SNOWTRACE }} FOUNDRY_PROFILE: "optimized" MNEMONIC: ${{ secrets.MNEMONIC }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28a40f2df..3f0810fa5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,6 @@ populate it with the appropriate environment values. You need to provide your mn To make CI work in your pull request, ensure that the necessary environment variables are configured in your forked repository's secrets. Please add the following variables in your GitHub Secrets: -- API_KEY_ETHERSCAN - API_KEY_INFURA - RPC_URL_MAINNET diff --git a/foundry.toml b/foundry.toml index 0ec326a6a..0b148369a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -78,16 +78,6 @@ out = "docs" repository = "https://github.com/sablier-labs/v2-core" -[etherscan] - arbitrum = { key = "${API_KEY_ARBISCAN}" } - avalanche = { key = "${API_KEY_SNOWTRACE" } - bnb_smart_chain = { key = "${API_KEY_BSCSCAN}" } - gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" } - mainnet = { key = "${API_KEY_ETHERSCAN}" } - optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" } - polygon = { key = "${API_KEY_POLYGONSCAN}" } - sepolia = { key = "${API_KEY_ETHERSCAN}" } - [fmt] bracket_spacing = true int_types = "long" From 5665d0533c80aa28af251e241af79a0017268989 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 10 Jan 2024 20:21:53 +0200 Subject: [PATCH 016/132] ci: remove submodulules in checkout --- .github/workflows/deploy-comptroller.yml | 2 -- .github/workflows/deploy-core.yml | 2 -- .github/workflows/deploy-lockup-dynamic.yml | 2 -- .github/workflows/deploy-lockup-linear.yml | 2 -- .github/workflows/deploy-nft-descriptor.yml | 2 -- .github/workflows/generate-svg.yml | 3 --- .github/workflows/run-smtchecker.yml | 2 -- 7 files changed, 15 deletions(-) diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml index f045c1346..ef16bf366 100644 --- a/.github/workflows/deploy-comptroller.yml +++ b/.github/workflows/deploy-comptroller.yml @@ -23,8 +23,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml index 031572599..c9368a01a 100644 --- a/.github/workflows/deploy-core.yml +++ b/.github/workflows/deploy-core.yml @@ -27,8 +27,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml index 7af3c6955..de24ed577 100644 --- a/.github/workflows/deploy-lockup-dynamic.yml +++ b/.github/workflows/deploy-lockup-dynamic.yml @@ -33,8 +33,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml index b75226c91..77e442870 100644 --- a/.github/workflows/deploy-lockup-linear.yml +++ b/.github/workflows/deploy-lockup-linear.yml @@ -29,8 +29,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml index 0f880ef41..2b338e7b7 100644 --- a/.github/workflows/deploy-nft-descriptor.yml +++ b/.github/workflows/deploy-nft-descriptor.yml @@ -19,8 +19,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/generate-svg.yml b/.github/workflows/generate-svg.yml index 1050b9992..6c2f0d0c9 100644 --- a/.github/workflows/generate-svg.yml +++ b/.github/workflows/generate-svg.yml @@ -22,9 +22,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - token: ${{ secrets.CI_TOKEN }} - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" diff --git a/.github/workflows/run-smtchecker.yml b/.github/workflows/run-smtchecker.yml index 69c91e6f7..89a68cafb 100644 --- a/.github/workflows/run-smtchecker.yml +++ b/.github/workflows/run-smtchecker.yml @@ -8,8 +8,6 @@ jobs: steps: - name: "Check out the repo" uses: "actions/checkout@v4" - with: - submodules: "recursive" - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" From 3035b4c4cae35b0713cc3c7627882a7864cde5dc Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 11 Jan 2024 16:23:20 +0200 Subject: [PATCH 017/132] chore: order vars alphabetically in .env.example --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 0b5c47463..5c5efc6ee 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ export API_KEY_INFURA="YOUR_API_KEY_INFURA" -export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET" export FOUNDRY_PROFILE="lite" export MNEMONIC="YOUR_MNEMONIC" +export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET" From b2282af8c4b4535d4fc1ef7a0372eee57b68901e Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 11 Jan 2024 17:59:41 +0200 Subject: [PATCH 018/132] ci: frozen lockfile --- .github/workflows/ci-deep.yml | 4 ++-- .github/workflows/ci-slither.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .github/workflows/multibuild.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index a7fe3e092..d21874883 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -44,7 +44,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Lint the code" run: "bun run lint" @@ -67,7 +67,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Show the Foundry config" run: "forge config" diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml index a2501b998..12d13b6f9 100644 --- a/.github/workflows/ci-slither.yml +++ b/.github/workflows/ci-slither.yml @@ -22,7 +22,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Lint the code" run: "bun run lint" @@ -46,7 +46,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Run Slither analysis" uses: "crytic/slither-action@v0.3.0" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc40dac28..cfc3dc238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Lint the code" run: "bun run lint" @@ -52,7 +52,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Show the Foundry config" run: "forge config" diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index 6ee1581bb..2b872f81a 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -16,7 +16,7 @@ jobs: uses: "oven-sh/setup-bun@v1" - name: "Install the Node.js dependencies" - run: "bun install" + run: "bun install --frozen-lockfile" - name: "Check that V2 Core can be built with multiple Solidity versions" uses: "PaulRBerg/foundry-multibuild@v1" From 90009c4956a8b3526f45e41eddaf330ad5b129f9 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 5 Jan 2024 19:28:40 +0200 Subject: [PATCH 019/132] ci: use reusable workflows --- .github/workflows/ci-deep.yml | 200 ++++------------------ .github/workflows/ci-slither.yml | 58 +------ .github/workflows/ci.yml | 274 ++++--------------------------- .github/workflows/stale.yml | 22 +-- 4 files changed, 68 insertions(+), 486 deletions(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index d21874883..351e6b66f 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -32,188 +32,46 @@ on: jobs: lint: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - name: "Lint the code" - run: "bun run lint" - - - name: "Add lint summary" - run: | - echo "## Lint result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-lint.yml@main" build: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - name: "Show the Foundry config" - run: "forge config" - - - name: "Produce an optimized build with --via-ir" - run: "FOUNDRY_PROFILE=optimized forge build" - - - name: "Build the test contracts" - run: "FOUNDRY_PROFILE=test-optimized forge build" - - - 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: "build-and-modules-${{ github.sha }}" - path: | - cache - node_modules - out - out-optimized - - - name: "Add build summary" - run: | - echo "## Build result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-build.yml@main" test-unit: - env: - FOUNDRY_FUZZ_RUNS: ${{ inputs.unitFuzzRuns || '100000' }} needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the unit tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/unit\"" - - - name: "Add test summary" - run: | - echo "## Unit tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: ${{ inputs.unitFuzzRuns || 100000 }} + foundry-profile: "test-optimized" + match-path: "test/unit/**/*.sol" + name: "Unit tests" test-integration: - env: - FOUNDRY_FUZZ_RUNS: ${{ inputs.integrationFuzzRuns || '100000' }} needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the integration tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/integration/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Integration tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: ${{ inputs.integrationFuzzRuns || 100000 }} + foundry-profile: "test-optimized" + match-path: "test/integration/**/*.sol" + name: "Integration tests" test-invariant: - env: - FOUNDRY_INVARIANT_DEPTH: ${{ inputs.invariantDepth || '100' }} - FOUNDRY_INVARIANT_RUNS: ${{ inputs.invariantRuns || '100' }} needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the invariant tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/invariant/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Invariant tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-invariant-depth: ${{ inputs.invariantDepth || 100 }} + foundry-invariant-runs: ${{ inputs.invariantRuns || 100 }} + foundry-profile: "test-optimized" + match-path: "test/invariant/**/*.sol" + name: "Invariant tests" test-fork: - env: - FOUNDRY_FUZZ_RUNS: ${{ inputs.forkFuzzRuns || '1000' }} needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the fork tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/fork/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Fork tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + secrets: + RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: ${{ inputs.forkFuzzRuns || 1000 }} + foundry-profile: "test-optimized" + match-path: "test/fork/**/*.sol" + name: "Fork tests" diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml index 12d13b6f9..aef1c9066 100644 --- a/.github/workflows/ci-slither.yml +++ b/.github/workflows/ci-slither.yml @@ -1,66 +1,12 @@ name: "CI Slither" -env: - 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@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - name: "Lint the code" - run: "bun run lint" - - - name: "Add lint summary" - run: | - echo "## Lint result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-lint.yml@main" slither-analyze: - runs-on: "ubuntu-latest" - permissions: - actions: "read" - contents: "read" - security-events: "write" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - 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 + uses: "sablier-labs/reusable-workflows/.github/workflows/slither-analyze.yml@main" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfc3dc238..adeb242da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,6 @@ concurrency: cancel-in-progress: true group: ${{github.workflow}}-${{github.ref}} -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} - on: workflow_dispatch: pull_request: @@ -17,257 +13,59 @@ on: jobs: lint: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - name: "Lint the code" - run: "bun run lint" - - - name: "Add lint summary" - run: | - echo "## Lint result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-lint.yml@main" build: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" - - - name: "Install the Node.js dependencies" - run: "bun install --frozen-lockfile" - - - name: "Show the Foundry config" - run: "forge config" - - - 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 and the node modules so that they can be re-used by the other jobs" - uses: "actions/cache/save@v3" - with: - key: "build-and-modules-${{ github.sha }}" - path: | - cache - node_modules - out - out-optimized - - - name: "Store the contract artifacts in CI" - uses: "actions/upload-artifact@v3" - with: - name: "contract-artifacts" - path: "artifacts" - - name: "Add build summary" - run: | - echo "## Build result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-build.yml@main" test-unit: needs: ["lint", "build"] - env: - FOUNDRY_FUZZ_RUNS: "5000" - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the unit tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/unit/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Unit tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: 5000 + foundry-profile: "test-optimized" + match-path: "test/unit/**/*.sol" + name: "Unit tests" test-integration: needs: ["lint", "build"] - env: - FOUNDRY_FUZZ_RUNS: "5000" - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the integration tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/integration/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Integration tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: 5000 + foundry-profile: "test-optimized" + match-path: "test/integration/**/*.sol" + name: "Integration tests" test-utils: needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the utils tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/utils/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Utils tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-profile: "test-optimized" + match-path: "test/utils/**/*.sol" + name: "Utils tests" test-invariant: needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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: "Run the invariant tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/invariant/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Invariant tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-profile: "test-optimized" + match-path: "test/invariant/**/*.sol" + name: "Invariant tests" test-fork: needs: ["lint", "build"] - env: - FOUNDRY_FUZZ_RUNS: "100" - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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 fuzz seed that changes weekly to avoid burning through RPC allowance" - run: | - echo "FOUNDRY_FUZZ_SEED=$(echo $(($EPOCHSECONDS / 604800)))" >> $GITHUB_ENV - - - name: "Run the fork tests against the optimized build" - run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/fork/**/*.sol\"" - - - name: "Add test summary" - run: | - echo "## Fork tests result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + secrets: + RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: 100 + foundry-profile: "test-optimized" + fuzz-seed: true + match-path: "test/fork/**/*.sol" + name: "Fork tests" coverage: needs: ["lint", "build"] - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - 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" - - - name: "Upload coverage report to Codecov" - uses: "codecov/codecov-action@v3" - with: - files: "./lcov.info" - - - name: "Add coverage summary" - run: | - echo "## Coverage result" >> $GITHUB_STEP_SUMMARY - echo "✅ Uploaded to Codecov" >> $GITHUB_STEP_SUMMARY + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" + with: + match-path: "test/{integration,unit}/**/*.sol" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 398801ecd..a717e9753 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,24 +7,4 @@ on: jobs: stale: - runs-on: "ubuntu-latest" - steps: - - uses: "actions/stale@v9" - with: - close-issue-message: "This issue was closed because it has been stalled for 14 days with no activity." - close-issue-reason: "not_planned" - close-pr-message: "This PR was closed because it has been stalled for 7 days with no activity." - days-before-issue-close: 14 - days-before-issue-stale: 182 - days-before-pr-close: 7 - days-before-pr-stale: 90 - exempt-issue-labels: "help,priority0" - operations-per-run: 1000 - stale-issue-label: "stale" - stale-issue-message: - 'This issue is stale because it has been open 6 months with no activity. Leave a comment or remove the - "stale" label, otherwise this will be closed in 14 days.' - stale-pr-label: "stale" - stale-pr-message: - 'This PR is stale because it has been open 3 months with no activity. Leave a comment or remove the "stale" - label, otherwise this will be closed in 7 days.' + uses: "sablier-labs/reusable-workflows/.github/workflows/stale.yml@main" From b78fce16326d9865c68e8b05859ffbc9fec92e54 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 12 Jan 2024 13:58:48 +0200 Subject: [PATCH 020/132] chore: change solarray dependency (#792) --- bun.lockb | Bin 43222 -> 43200 bytes package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lockb b/bun.lockb index 240f58ac02d86563e82730c3ce788cc177f815b8..11a133d47dd94cfb065836d9c538241f1304cae3 100755 GIT binary patch delta 3297 zcmZ`*4Nz3q6~1?2mCN6{BE`o;0a24$U4;iOk?IAb;;N`*OwmSb7hT1;Km>}S=&t;z zm>7$vHEm2Wu}-yGGd7!d}Ke`=^{+vi{I#+cza2JNw|% z`bpgj%6PE5JH!7vXDpGiaFf3}7+{R;jo~v6OTPg!8TQIJ#xfvhK_)@g#q3YVTlQi| zrSF4Gfy{DR^Ouw0*`Y^3Y0%z+90qv>(goQVsBI23FxE4eF#+7-4+hsXHnCk`p>VK% zrN6O;u@G=7@P!0xwQ(>iRt+ma89&E>Rs7mDb!%!70K(KCfF7(u;f$DrLMl)TqzZ5r zQl-BVG97X;l=uwK!!R6jb$yc==oE5N{s$q|{I_EG6-fMruR*Eo7a_4!co&o^ZY!jl ztzh9b_)rXuAy$CJrh$cFH3QiCwSksqwc>lwDKi5m zHhclS^1lSVvahJ|2iJn*Rn5w!#@{$$RnWisePG4)ziJ`$xER{tpvYcACTij1kfR_C z1XjBj&9dYPNaPo;0t@9=9V7n#7OsjVu-ibJ?XQ(zfnE_WU1abh9^ zH%Hk_n!J*tsZwl*ZU%IN%}7_s=aSCJ*zZ!>B}#ZRMO{*y0k+l#PiHF1q?r0#C43fj z4UxQwqC=#33tHvlB=F;@gKp;Nh;Kd?;D9?0=D*A&HId^ z&=ugFP-}APPVw?O@?}f$5p<7P@pOtp*P3M&Nu0T3mt)A{osPFeoi<|N41WluW}EdO zUIi)vN;GfxW%A`pF?gi4bAt(ain&1QWUN^2K#C(X{of_uD9ImC*C;6@9vXEyVM+Fi z-9Sr$aPp|SPso=ixumW+pyP_sg%^K^2{)PsBi@&JQJK31TLOJ-qLuHHfJqZc? z6%wPR)(4e(opFrjW7wSUDe|CZu8@E96OPYwB0ER-OiX8Z#*~)>UN1BRnwr)G8jeJ! zF51ocvPj>v<#EmrQEI7?vPB^tnY3(&Ba*W$oW-;0jg}ESNT*v2UP_<0RPZV)+i2+a zi#w3|RNc_@xjqN~LH;BUe%V^uy-~yC@av7Md5GMb48DtIV%$r=ZPjScrcC}i9otmF zm(!P=+`S0`BKAQE9{V%|)2wwT9WZDd` zO8VON<;8TNRnzUZ<3>Sg(v*R6!i)kduIXE3w;|Q*Mo%qGauvtyh-fz^{fm!W^xfZo z)4{jod-6TFXjiCWv!>fE%C#M1|26Ho9Rf4+t;mmP>*fmHLx0+A@Cy{T#nA1p;&@Hg z*C(njUHgXjII7%Ifk$pX#$$A6i>9mppm@W=_n*!F-kH-|5=};kjHi)uLmFR6B_U0> z`;v9rp7{AW_Sci<>fo2p&Qg8I(Cz-Dc+UB|1^Y5LIC!C_z>|+Cd2|xZy4-` zWq+T3fhbq$cO3@rqfZd)f9qS7w}DKLQ+B7J+r8J{5ASph3=C3tEp{VMP;IBC+dbIr zht(f1PfIBL#$H8lbZWSNy%?|37?oQofnV@B*Q-lD17X7YS$-?oH5 pNgr=pKRovCO|;*=yx7ARS+_kc$F@$etrKEa;xA@JqK8uWzX8|i6jJ~I delta 3309 zcmZ`+4^WiX5r6OSl*b>>0}cK7Kt!$4L=TSxze^}SZBTL=R9e)em8N%!NClBURS|(h zQ8_1Rf@@Mc+R)Ud)|jNNOlnf=h%q*~Sfbd9W2-h9r>PCm)M=8Y*wp^s_uXflbPCMd z@3*^e-|pMpH%o87W1!#hq$fMtdhu_+no_l8X#aP8#)rS&Roi>AZ{^VL_r5mxG4tMR zd3bKu!r8p8t1B(|9A_+nv2bHBR9(Rs+Y`el9TvX@Gzs!0ag3#b&Ie5dZHUPq9A?Q2 zK^6ZjXfkNF)7rm+1kY-_1(XWzAn0h&i=ZyhhKibX74?km8^M?WZVFacS2Z-Uo$x~8 z>e>~-hEhJ%Mohs8qztu! zDg&oLRrpn)V?fKn#Amn^%a=eaYa2~NClHg;KLD!sACBR@p!f@422;t;f#Rs}PB4|- zc2GB4&cbW(p*-}DvJ8})0v2|f@gD@SfXU)|UMs190!efSLfL6yVB zFskrmiZ~4S>rhq4uZBq7Z!h&b(%N1HSJ`Tg-RfFUg%=>9O1lVDIqO8kI5vD0I1{v@ zzP`48TE&JT@Rj~~@RfY|s$lhM_;^XPVp$bzn6|PySQ!OYzJ8$=+HM!ab|@%k&m$6b z@XMg%LH#hSZtv|3iyj9>eBovALg`h;9RGg@FN*~fT+>)xpT}76JLVlStK1S<_?|4r z(qU*$&yBdWVZ4(>yyQnI5HE!bduKp2j7k&y6b1hi5<>D^3Sf;;L`ZQO#r_rOIH^k* zJds3#M%PmhPo!qU4n% zk|ckT0$5Whf^{xMlcZ=J&e#G|*Bx(&-vKQG;-<9>iX=;3OVMO0UO@BQ56N)z)c1hw zcnpz&hEX!pKfZ*bBc*r@ydv;Mn3gV5z$KjpxaL{(xG3Pw6m>~)64*K$emYZ89e(O_ z74Z2K86|lWMMp_-7+j^}B>2ZuDd3iT2Su=+qo`X7H&Xf#7f2ZL%a{9oU$%sE~-t18b@6zhH`F<6e%cSl>#eeWk5>9O4)9p=_cw=HpK6NRC2Lf z7{Z-mB>EXQXa*d5%f_&lj5_OhIO%Cih{Qh9Y6QBjkkeRRHlYVxy!ciPBZvC zil$4k89Wu6Sx%xCNO=d8Xz(G5=u!mHl!|BF%pM@C1>7izyYM2+qds?m^V|3eQD0I4 ze~qFUQaI7#$}S@$j6XnuOeww(UM_eJawi#lkfNE=nUk(c3du+L2gah9fUUb$`#z>9 zcm|#abtb2-WP>+QAWMpOz`N}gPp2q&?HN{)#KC)id<j4F1+t|`8f#tL2tt@*5s*rZWvdfNxyVfY-%?<_K_2*gCG zT>(qI$;hJl1g`UX@;xY-YZRP#w?kz2?3nmW&KM^iFQw&x*4p}t#>T3O`k(g{mOa6F zsHbmnah&r4Ds5!X?6NlAGrhdi(KD_*oWUp3vrU=2j*d0?_#FC2Qwd*2vp4#5`<)#a zdEc6pG4lfs{w?ox4}RHNdSau7x8cCXO5Q>4W*^^4bFl8AUvAQ9XLCA#j$Ujo;VbB7 zv!>g_!R$w6@vwt?K7^e-(+q2&oK2dwOSeaiZ}7c;n)}c0wb06kmY1>l)B>#~bj#M| zg>-6@rrX2DmE2j0_YV{kcH~-iP2GHZ_z2ZaES#0-^2g+`XpbZP4?lk<@KN_)9K6-* z@p{l_7pbI0)9u0JLg%Fa%=~7jz)r7a`4+Xel<<9Yy2Z!OP+Y4|w`Yl8tjf6co26$j zeC~G+mA01PjqApGh_1D2x;<}vv^Z-?@3Gbd(<4}Btdz3bG+spoZJKURBX!&E{=pmU zoulUI@XyOmQEi(~x2F>Sytl6B?n&R^;CY^0j~7-Z(^2fVhXI#%&6B@-sfs&xlO=Qm zr<7A-SkvthB)RT;52Rmt>{DpXuwrZ{8P<@|@^($PCz^+*PU_h=DLXgjF%COGkHd;R z`2+{vJv)5UyQPr(EGsAIIILJ&_8e4trL?U`yfS2ZgoqfsOs;k<-yV04{QIC==KZA7 zv|`?iJ?Ly%B*t%eX8l1(RPEsXF#Y2z{yIIixkR@|rbmulckaD>Z8B`B+JbT~eFiN* z&EMifAGdAM^6kOtrHe;C$ZnXL9`h0TSc+#-HDvdf!&C3wS`iw}XBOsp?(^ic^VEm^ zSBZCM+(~+errTrHCu^SGJUZd06JP~#suQ=>%~DT+%|{Lpe@@T;WO#dw)L3} v_~!yI)3oYfs3FIG{3gU+zn<#tspF>HsdDG{G+TXIOr36Y>OF_{kL3Rak@h0u diff --git a/package.json b/package.json index 9532572d5..ffffc4e16 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "forge-std": "github:foundry-rs/forge-std#v1.5.6", "prettier": "^2.8.8", "solady": "0.0.129", - "solarray": "github:sablier-labs/solarray#6bf10cb", + "solarray": "github:evmcheb/solarray#a547630", "solhint": "^4.0.0" }, "files": [ From 7819a3b5122036596edff3326b97a8c03750bbb8 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 16 Jan 2024 19:20:31 +0200 Subject: [PATCH 021/132] build: multi-chain deployment script (#748) * build: add deploy multi chains script build: remove etherscan api keys in foundry.toml feat: add deploy core 3 scripts chore: improve .env.example file * build: add arbitrum sepolia chore: git ignore deployments dir * chore: update wording in scripts chore: remove forge fmt comment * refactor: separate base env from deployment env chore: improve multi-chain deployment script refactor: rename env var MAX_SEGMENT_COUNT * refactor: rename multi-chain script * chore: fix arbitrum config key * fix: use array to create deployment command * chore: create an array for deployment command * Powerful command line options for deployment script (#752) * build: add script to generate deployment command * feat: new command-line options for deploy-multi-chain command * chore: continue for warnings and throw for errors * perf: polish deployment script --------- Co-authored-by: Paul Razvan Berg * refactor: hard code admin addresses --------- Co-authored-by: andreivladbrg Co-authored-by: smol-ninja --- .env.deployment.example | 30 ++ .gitignore | 2 + script/DeployCore3.s.sol | 35 +++ script/DeployDeterministicCore.s.sol | 1 - script/DeployDeterministicCore2.s.sol | 1 - script/DeployDeterministicCore3.s.sol | 42 +++ shell/deploy-multi-chain.sh | 430 ++++++++++++++++++++++++++ 7 files changed, 539 insertions(+), 2 deletions(-) create mode 100644 .env.deployment.example create mode 100644 script/DeployCore3.s.sol create mode 100644 script/DeployDeterministicCore3.s.sol create mode 100755 shell/deploy-multi-chain.sh diff --git a/.env.deployment.example b/.env.deployment.example new file mode 100644 index 000000000..39ff9e303 --- /dev/null +++ b/.env.deployment.example @@ -0,0 +1,30 @@ +# Used by the multi-chain deployment script + +# General +export MAX_SEGMENT_COUNT="THE_MAX_SEGMENT_COUNT" +export MNEMONIC="YOUR_MNEMONIC" + +# RPC URLs +export ARBITRUM_RPC_URL="YOUR_RPC_URL" +export ARBITRUM_SEPOLIA_RPC_URL="YOUR_RPC_URL" +export AVALANCHE_RPC_URL="YOUR_RPC_URL" +export BASE_RPC_URL="YOUR_RPC_URL" +export BSC_RPC_URL="YOUR_RPC_URL" +export GNOSIS_RPC_URL="YOUR_RPC_URL" +export MAINNET_RPC_URL="YOUR_RPC_URL" +export OPTIMISM_RPC_URL="YOUR_RPC_URL" +export POLYGON_RPC_URL="YOUR_RPC_URL" +export SCROLL_RPC_URL="YOUR_RPC_URL" +export SEPOLIA_RPC_URL="YOUR_RPC_URL" + +# Etherscan API keys +export ARBISCAN_API_KEY="YOUR_API_KEY" +export BASESCAN_API_KEY="YOUR_API_KEY" +export BSCSCAN_API_KEY="YOUR_API_KEY" +export ETHERSCAN_API_KEY="YOUR_API_KEY" +export GNOSISSCAN_API_KEY="YOUR_API_KEY" +export OPTIMISTIC_API_KEY="YOUR_API_KEY" +export POLYGONSCAN_API_KEY="YOUR_API_KEY" +export SCROLLSCAN_API_KEY="YOUR_API_KEY" +export SNOWTRACE_API_KEY="YOUR_API_KEY" + diff --git a/.gitignore b/.gitignore index dfe17c873..7a74302fe 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ artifacts broadcast cache coverage +deployments docs node_modules out @@ -11,6 +12,7 @@ out-svg # files *.env +*.env.deployment *.log .DS_Store .pnp.* diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol new file mode 100644 index 000000000..97381135d --- /dev/null +++ b/script/DeployCore3.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19 <0.9.0; + +import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; +import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @notice Deploys these contracts in the following order: +/// +/// 1. {SablierV2NFTDescriptor} +/// 2. {SablierV2LockupDynamic} +/// 3. {SablierV2LockupLinear} +contract DeployCore3 is BaseScript { + function run( + address initialAdmin, + ISablierV2Comptroller comptroller, + uint256 maxSegmentCount + ) + public + virtual + broadcast + returns ( + SablierV2NFTDescriptor nftDescriptor, + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear + ) + { + nftDescriptor = new SablierV2NFTDescriptor(); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); + } +} diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index aac8a7ab9..58d8de483 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -37,7 +37,6 @@ contract DeployDeterministicCore is BaseScript { bytes32 salt = bytes32(abi.encodePacked(create2Salt)); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - // forgefmt: disable-next-line lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 71015d65e..809dac843 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -35,7 +35,6 @@ contract DeployDeterministicCore2 is BaseScript { { bytes32 salt = bytes32(abi.encodePacked(create2Salt)); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); - // forgefmt: disable-next-line lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol new file mode 100644 index 000000000..74ab49c95 --- /dev/null +++ b/script/DeployDeterministicCore3.s.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19 <0.9.0; + +import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; +import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @notice Deploys these contracts at deterministic addresses across chains, in the following order: +/// +/// 1. {SablierV2NFTDescriptor} +/// 2. {SablierV2LockupDynamic} +/// 3. {SablierV2LockupLinear} +/// +/// @dev Reverts if any contract has already been deployed. +contract DeployDeterministicCore3 is BaseScript { + /// @dev The presence of the salt instructs Forge to deploy the contract via a deterministic CREATE2 factory. + /// https://github.com/Arachnid/deterministic-deployment-proxy + function run( + string memory create2Salt, + address initialAdmin, + ISablierV2Comptroller comptroller, + uint256 maxSegmentCount + ) + public + virtual + broadcast + returns ( + SablierV2NFTDescriptor nftDescriptor, + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear + ) + { + bytes32 salt = bytes32(abi.encodePacked(create2Salt)); + nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); + } +} diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh new file mode 100755 index 000000000..98def7eca --- /dev/null +++ b/shell/deploy-multi-chain.sh @@ -0,0 +1,430 @@ +#!/usr/bin/env bash + +# Pre-requisites for running this script: +# +# - bash >=4.0.0 +# - foundry (https://getfoundry.sh) + +# Usage: ./shell/deploy-multi-chain.sh [options] [[chain1 chain2 ...]] +# Enters interactive mode if no `.env.deployment` file is found +# +# Options: +# --all Deploy on all chains. +# --broadcast Broadcast the deployment and verify on Etherscan. +# --deterministic Deploy using the deterministic script. +# -h, --help Show available command-line options and exit. +# -i, --interactive Enters interactive mode and ignore .env.deployment. +# --print Simulate and show the deployment command. +# -s, --script Script to run from the `script` folder. +# --with-gas-price Specify gas price for transaction. +# +# Example: ./shell/deploy-multi-chain.sh # By default, deploys to Sepolia only +# Example: ./shell/deploy-multi-chain.sh --broadcast optimism polygon +# Example: ./shell/deploy-multi-chain.sh --broadcast --deterministic --print optimism +# +# Make sure to set up your `.env.deployment` file first. + +# Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca +set -euo pipefail + +# Color codes +EC='\033[0;31m' # Error Color +IC='\033[0;36m' # Info Color +NC='\033[0m' # No Color +SC='\033[0;32m' # Success Color +WC='\033[0;33m' # Warn Color + +# Unicode characters for tick +TICK="\xE2\x9C\x94" + +# Check: Bash >=4.0.0 is required for associative arrays +if ((BASH_VERSINFO[0] < 4)); then + echo -e "${EC}Error:\nThis script requires Bash version 4.0.0 or higher. + \nYou are currently using Bash version ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}. + \nPlease upgrade your Bash version and try again.${NC}" + exit 1 +fi + +# Define usage +usage="\nUsage: ./shell/deploy-multi-chain.sh [-h] [--help] [--print] [-i] [--interactive] [-s] [--script] + [--broadcast] [--deterministic] [--with-gas-price] [--all] + [[chain1 chain2 ...]] +Examples: + ./shell/deploy-multi-chain.sh # By default, deploys only to Sepolia + ./shell/deploy-multi-chain.sh --broadcast optimism polygon + ./shell/deploy-multi-chain.sh --broadcast --deterministic optimism +" + +# Create deployments directory +deployments=./deployments +rm -rf ${deployments} +mkdir ${deployments} + +# Addresses taken from https://docs.sablier.com/contracts/v2/deployments +ARBITRUM_COMPTROLLER="0x17Ec73692F0aDf7E7C554822FBEAACB4BE781762" +ARBITRUM_SEPOLIA_COMPTROLLER="0xA6A0cfA3442053fbB516D55205A749Ef2D33aed9" +AVALANCHE_COMPTROLLER="0x66F5431B0765D984f82A4fc4551b2c9ccF7eAC9C" +BASE_COMPTROLLER="0x7Faaedd40B1385C118cA7432952D9DC6b5CbC49e" +BSC_COMPTROLLER="0x33511f69A784Fd958E6713aCaC7c9dCF1A5578E8" +GNOSIS_COMPTROLLER="0x73962c44c0fB4cC5e4545FB91732a5c5e87F55C2" +MAINNET_COMPTROLLER="0xC3Be6BffAeab7B297c03383B4254aa3Af2b9a5BA" +OPTIMISM_COMPTROLLER="0x1EECb6e6EaE6a1eD1CCB4323F3a146A7C5443A10" +POLYGON_COMPTROLLER="0x9761692EDf10F5F2A69f0150e2fd50dcecf05F2E" +SCROLL_COMPTROLLER="0x859708495E3B3c61Bbe19e6E3E1F41dE3A5C5C5b" +SEPOLIA_COMPTROLLER="0x2006d43E65e66C5FF20254836E63947FA8bAaD68" + +# Addresses taken from https://docs.sablier.com/concepts/governance +export ARBITRUM_ADMIN="0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376" +export ARBITRUM_SEPOLIA_ADMIN="0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F" +export AVALANCHE_ADMIN="0x4735517616373c5137dE8bcCDc887637B8ac85Ce" +export BASE_ADMIN="0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66" +export BSC_ADMIN="0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3" +export GNOSIS_ADMIN="0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399" +export MAINNET_ADMIN="0x79Fb3e81aAc012c08501f41296CCC145a1E15844" +export OPTIMISM_ADMIN="0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350" +export POLYGON_ADMIN="0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6" +export SCROLL_ADMIN="0x0F7Ad835235Ede685180A5c611111610813457a9" +export SEPOLIA_ADMIN="0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F" + +# Declare the chain IDs +ARBITRUM_CHAIN_ID="42161" +ARBITRUM_SEPOLIA_CHAIN_ID="421614" +AVALANCHE_CHAIN_ID="43114" +BASE_CHAIN_ID="8453" +BSC_CHAIN_ID="56" +GNOSIS_CHAIN_ID="100" +MAINNET_CHAIN_ID="1" +OPTIMISM_CHAIN_ID="10" +POLYGON_CHAIN_ID="137" +SCROLL_CHAIN_ID="534352" +SEPOLIA_CHAIN_ID="11155111" + +# Flag for broadcast deployment +BROADCAST_DEPLOYMENT=false + +# Flag for deterministic deployment +DETERMINISTIC_DEPLOYMENT=false + +# Flags for gas price +GAS_PRICE=0 +WITH_GAS_PRICE=false + +# Flag for all chains +ON_ALL_CHAINS=false + +# Flag for displaying deployement command +READ_ONLY=false + +# Flag to enter interactive mode in case .env.deployment not found or --interactive is provided +INTERACTIVE=false + +# Provided chains +provided_chains=() + +# Script to execute +sol_script="" + +# Declare the chains array +declare -A chains + +# define function to initialize all configurations +function initialize { + chains["arbitrum"]="$ARBITRUM_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_CHAIN_ID $ARBITRUM_ADMIN $ARBITRUM_COMPTROLLER" + chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_CHAIN_ID $ARBITRUM_SEPOLIA_ADMIN $ARBITRUM_SEPOLIA_COMPTROLLER" + chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_CHAIN_ID $AVALANCHE_ADMIN $AVALANCHE_COMPTROLLER" + chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_CHAIN_ID $BASE_ADMIN $BASE_COMPTROLLER" + chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_CHAIN_ID $BSC_ADMIN $BSC_COMPTROLLER" + chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_CHAIN_ID $GNOSIS_ADMIN $GNOSIS_COMPTROLLER" + chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_CHAIN_ID $MAINNET_ADMIN $MAINNET_COMPTROLLER" + chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_CHAIN_ID $OPTIMISM_ADMIN $OPTIMISM_COMPTROLLER" + chains["polygon"]="$POLYGON_RPC_URL $POLYGONSCAN_API_KEY $POLYGON_CHAIN_ID $POLYGON_ADMIN $POLYGON_COMPTROLLER" + chains["sepolia"]="$SEPOLIA_RPC_URL $ETHERSCAN_API_KEY $SEPOLIA_CHAIN_ID $SEPOLIA_ADMIN $SEPOLIA_COMPTROLLER" + chains["scroll"]="$SCROLL_RPC_URL $SCROLLSCAN_API_KEY $SCROLL_CHAIN_ID $SCROLL_ADMIN $SCROLL_COMPTROLLER" +} + +# define function to initialize limited configurations +function initialize_interactive { + # load values from the terminal prompt + echo -e "1. Enter admin address: \c" + read admin + + echo -e "2. Enter Etherscan API key: \c" + read api_key + + echo -e "3. Enter max segment count: \c" + read MAX_SEGMENT_COUNT + + # chain id and comptroller only + chains["arbitrum"]="$ARBITRUM_CHAIN_ID $ARBITRUM_COMPTROLLER" + chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_CHAIN_ID $ARBITRUM_SEPOLIA_COMPTROLLER" + chains["avalanche"]="$AVALANCHE_CHAIN_ID $AVALANCHE_COMPTROLLER" + chains["base"]="$BASE_CHAIN_ID $BASE_COMPTROLLER" + chains["bnb_smart_chain"]="$BSC_CHAIN_ID $BSC_COMPTROLLER" + chains["gnosis"]="$GNOSIS_CHAIN_ID $GNOSIS_COMPTROLLER" + chains["mainnet"]="$MAINNET_CHAIN_ID $MAINNET_COMPTROLLER" + chains["optimism"]="$OPTIMISM_CHAIN_ID $OPTIMISM_COMPTROLLER" + chains["polygon"]="$POLYGON_CHAIN_ID $POLYGON_COMPTROLLER" + chains["sepolia"]="$SEPOLIA_CHAIN_ID $SEPOLIA_COMPTROLLER" + chains["scroll"]="$SCROLL_CHAIN_ID $SCROLL_COMPTROLLER" +} + +if [ -f .env.deployment ]; then + # Source the .env.deployment file to load the variables + source .env.deployment + + # initialize chains with all the configurations + initialize +else + # Set bool to enter intaractive mode + INTERACTIVE=true + + # load values from the terminal prompt + echo -e "${WC}Missing '.env.deployment'. Provide details below: ${NC}\n" + + # initialize chains with chain id and comptroller + initialize_interactive + +fi + +# Check for arguments passed to the script +for ((i=1; i<=$#; i++)); do + # Convert the argument to lowercase + arg=${!i,,} + + # Check if '--all' flag is provided in the arguments + if [[ ${arg} == "--all" ]]; then + ON_ALL_CHAINS=true + provided_chains=("${!chains[@]}") + fi + + # Check if '--broadcast' flag is provided the arguments + if [[ ${arg} == "--broadcast" ]]; then + BROADCAST_DEPLOYMENT=true + fi + + # Check if '--deterministic' flag is provided in the arguments + if [[ ${arg} == "--deterministic" ]]; then + echo -e "\nWhat version is this deployment? (1.1.1 or 1.1.2): \c" + read VERSION + if [[ "${VERSION}" != "1.1.1" && "${VERSION}" != "1.1.2" ]]; then + echo -e "\n${EC}Invalid version. Please enter either 1.1.1 or 1.1.2${NC}" + exit 1 + fi + DETERMINISTIC_DEPLOYMENT=true + fi + + # Show usage of this command with --help option + if [[ ${arg} == "--help" || ${arg} == "-h" ]]; then + echo -e "${usage}" + # Get all chain names from the chains array + names=("${!chains[@]}") + # Sort the names + sorted_names=($(printf "%s\n" "${names[@]}" | sort)) + # Print the header + printf "\nSupported chains: \n%-20s %-20s\n" "Chain Name" "Chain ID" + printf "%-20s %-20s\n" "-----------" "-----------" + + # Print the chains and their Chain IDs + for chain in "${sorted_names[@]}"; do + IFS=' ' read -r rpc_url api_key chain_id admin comptroller <<< "${chains[$chain]}" + + # Print the chain and Chain ID + printf "%-20s %-20s\n" "${chain}" "${chain_id}" + done + exit 0 + fi + + # Check if '--interactive' flag is provided in the arguments + if [[ ${arg} == "--interactive" || ${arg} == "-i" ]]; then + INTERACTIVE=true + echo -e "Interactive mode activated. Provide details below: \n" + + # initialize only chain id and comptroller + initialize_interactive + fi + + # Check if '--print' flag is provided in the arguments + if [[ ${arg} == "--print" ]]; then + READ_ONLY=true + fi + + # Check if '--script' flag is provided in the arguments + if [[ ${arg} == "--script" || ${arg} == "-s" ]]; then + files=(script/*.s.sol) + + # Present the list of available scripts + echo "Please select a script:" + select file in "${files[@]}"; do + if [[ -n ${file} ]]; then + echo -e "${SC}+${NC} You selected ${IC}${file}${NC}" + sol_script=${file} + break + else + echo -e "${EC}Invalid selection${NC}" + fi + done + fi + + # Check if '--with-gas-price' flag is provided in the arguments + if [[ ${arg} == "--with-gas-price" ]]; then + WITH_GAS_PRICE=true + + # Increment index to get the next argument, which should be the gas price + ((i++)) + GAS_PRICE=${!i} + if ! [[ ${GAS_PRICE} =~ ^[0-9]+$ ]]; then + echo -e "${EC}Error: Invalid value for --with-gas-price, must be number${NC}" + exit 1 + fi + fi + + # Check for passed chains + if [[ ${arg} != "--all" && + ${arg} != "--broadcast" && + ${arg} != "--deterministic" && + ${arg} != "--help" && + ${arg} != "-h" && + ${arg} != "-i" && + ${arg} != "--interactive" && + ${arg} != "--print" && + ${arg} != "-s" && + ${arg} != "--script" && + ${arg} != "--with-gas-price" && + ${ON_ALL_CHAINS} == false + ]]; then + # check for synonyms + if [[ ${arg} == "ethereum" ]]; then + arg="mainnet" + fi + provided_chains+=("${arg}") + fi +done + +# Set the default chain to Sepolia if no chains are provided +if [ ${#provided_chains[@]} -eq 0 ]; then + provided_chains=("sepolia") +fi + +# Compile the contracts +echo "Compiling the contracts..." + +# Deploy to the provided chains +for chain in "${provided_chains[@]}"; do + # Check if the provided chain is defined + if [[ ! -v "chains[${chain}]" ]]; then + printf "\n${WC}Warning for '${chain}': Invalid command or chain name. Get the full list of supported chains: ${NC}" + printf "\n\n\t${IC}./shell/deploy-multi-chain.sh --help${NC}\n" + continue + fi + + echo -e "\n${IC}Deployment on ${chain} started...${NC}" + + if [[ ${INTERACTIVE} == true ]]; then + # load values from the terminal prompt + echo -e "Enter RPC URL for ${chain}: \c" + read rpc_url + + # Get the values from the chains array + IFS=' ' read -r chain_id comptroller <<< "${chains[$chain]}" + else + # Split the configuration into RPC, API key, Chain ID, admin, and comptroller + IFS=' ' read -r rpc_url api_key chain_id admin comptroller <<< "${chains[$chain]}" + fi + + # Declare the deployment command + declare -a deployment_command + + deployment_command=("forge") + + # Construct the deployment command + if [[ ${DETERMINISTIC_DEPLOYMENT} == true ]]; then + echo -e "${SC}+${NC} Deterministic address" + if [[ ${sol_script} == "" ]]; then + deployment_command+=("script" "script/DeployDeterministicCore3.s.sol") + else + deployment_command+=("script" "${sol_script}") + fi + deployment_command+=("--rpc-url" "${rpc_url}") + + #################################################################### + # Distinct ways to construct command with string elements + # While execution adds single quotes around them while + # echo removes single quotes + #################################################################### + if [[ ${READ_ONLY} == true ]]; then + deployment_command+=("--sig" "'run(string,address,address,uint256)'") + deployment_command+=("'ChainID ${chain_id}, Version ${VERSION}'") + else + deployment_command+=("--sig" "run(string,address,address,uint256)") + deployment_command+=("ChainID ${chain_id}, Version ${VERSION}") + fi + else + # Construct the command + if [[ ${sol_script} == "" ]]; then + deployment_command+=("script" "script/DeployCore3.s.sol") + else + deployment_command+=("script" "${sol_script}") + fi + deployment_command+=("--rpc-url" "${rpc_url}") + + if [[ ${READ_ONLY} == true ]]; then + deployment_command+=("--sig" "'run(address,address,uint256)'") + else + deployment_command+=("--sig" "run(address,address,uint256)") + fi + fi + + deployment_command+=("${admin}") + deployment_command+=("${comptroller}") + deployment_command+=("${MAX_SEGMENT_COUNT}") + deployment_command+=("-vvv") + + # Append additional options if gas price is enabled + if [[ ${WITH_GAS_PRICE} == true ]]; then + gas_price_in_gwei=$(echo "scale=2; ${GAS_PRICE} / 1000000000" | bc) + echo -e "${SC}+${NC} Max gas price: ${gas_price_in_gwei} gwei" + deployment_command+=("--with-gas-price" "${GAS_PRICE}") + fi + + # Append additional options if broadcast is enabled + if [[ ${BROADCAST_DEPLOYMENT} == true ]]; then + echo -e "${SC}+${NC} Broadcasting on-chain" + deployment_command+=("--broadcast" "--verify" "--etherscan-api-key" "${api_key}") + else + echo -e "${SC}+${NC} Simulating on forked chain" + fi + + if [[ ${READ_ONLY} == true ]]; then + # Print deployment_command + echo -e "${SC}+${NC} Printing command without action\n" + echo -e "FOUNDRY_PROFILE=optimized ${deployment_command[@]}" + else + # Execute the deployment command and print the logs in real-time + output=$(FOUNDRY_PROFILE=optimized "${deployment_command[@]}" |& tee /dev/fd/2) || true + + # Check for error in output + if [[ ${output} == *"Error"* ]]; then + exit 1 + fi + + # Create a file for the chain + chain_file="${deployments}/${chain}.txt" + touch "${chain_file}" + + # Extract and save contract addresses + lockupDynamic_address=$(echo "${output}" | awk '/lockupDynamic: contract/{print $NF}') + lockupLinear_address=$(echo "${output}" | awk '/lockupLinear: contract/{print $NF}') + nftDescriptor_address=$(echo "${output}" | awk '/nftDescriptor: contract/{print $NF}') + + # Save to the chain file + { + echo "SablierV2LockupDynamic = ${lockupDynamic_address}" + echo "SablierV2LockupLinear = ${lockupLinear_address}" + echo "SablierV2NFTDescriptor = ${nftDescriptor_address}" + } >> "$chain_file" + + echo -e "${SC}${TICK} Deployed on ${chain}. You can find the addresses in ${chain_file}${NC}" + fi +done + +echo -e "\nEnd of it." From fe8a082927cd45e44afda5b603193ce0abac098c Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 1 Feb 2024 14:14:46 +0200 Subject: [PATCH 022/132] docs: increase bug bounty --- SECURITY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c1a2951ad..151302b1f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,8 +12,8 @@ report it to us. Starting on July 1, 2023, the [sablier-labs/v2-core](https://github.com/sablier-labs/v2-core) repository is subject to the Sablier V2 Bug Bounty (the "Program") to incentivize responsible bug disclosure. -We are limiting the scope of the Program to critical and high severity bugs, and are offering a reward of up to $50,000. -Happy hunting! +We are limiting the scope of the Program to critical and high severity bugs, and are offering a reward of up to +$100,000. Happy hunting! ### Scope @@ -57,7 +57,7 @@ vulnerability, it must adhere to these assumptions as well: ### Rewards Rewards will be allocated based on the severity of the bug disclosed and will be evaluated and rewarded at the -discretion of the Sablier Labs team. For critical bugs that lead to any loss of user funds, rewards of up to $50,000 +discretion of the Sablier Labs team. For critical bugs that lead to any loss of user funds, rewards of up to $100,000 will be granted. Lower severity bugs will be rewarded at the discretion of the team. ### Disclosure From 698dcb3b2d6758e2f79d9ad66d78abb127516f19 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 2 Feb 2024 13:24:36 +0200 Subject: [PATCH 023/132] chore: ignore node_modules in slither config --- slither.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither.config.json b/slither.config.json index 16f73fce4..30e1b8587 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,6 +1,6 @@ { "detectors_to_exclude": "naming-convention,reentrancy-events,solc-version,timestamp", - "filter_paths": "(test)", + "filter_paths": "(node_modules,test)", "solc_remaps": [ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@prb/math/=node_modules/@prb-math/", From 2b65c464a40fe0924ef1c3ce0aa24a0d90b3abf8 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 2 Feb 2024 14:16:05 +0200 Subject: [PATCH 024/132] ci: rename mnemonic env var --- .github/workflows/deploy-comptroller.yml | 2 +- .github/workflows/deploy-core.yml | 2 +- .github/workflows/deploy-lockup-dynamic.yml | 2 +- .github/workflows/deploy-lockup-linear.yml | 2 +- .github/workflows/deploy-nft-descriptor.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml index ef16bf366..2b4f1cd3b 100644 --- a/.github/workflows/deploy-comptroller.yml +++ b/.github/workflows/deploy-comptroller.yml @@ -3,7 +3,7 @@ name: "Deploy Comptroller" env: API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.MNEMONIC }} + MNEMONIC: ${{ secrets.EVM_MNEMONIC }} on: workflow_dispatch: diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml index c9368a01a..f3fb8d5fb 100644 --- a/.github/workflows/deploy-core.yml +++ b/.github/workflows/deploy-core.yml @@ -3,7 +3,7 @@ name: "Deploy Core" env: API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.MNEMONIC }} + MNEMONIC: ${{ secrets.EVM_MNEMONIC }} on: workflow_dispatch: diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml index de24ed577..0792d2da8 100644 --- a/.github/workflows/deploy-lockup-dynamic.yml +++ b/.github/workflows/deploy-lockup-dynamic.yml @@ -3,7 +3,7 @@ name: "Deploy Lockup Dynamic" env: API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.MNEMONIC }} + MNEMONIC: ${{ secrets.EVM_MNEMONIC }} on: workflow_dispatch: diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml index 77e442870..951dda899 100644 --- a/.github/workflows/deploy-lockup-linear.yml +++ b/.github/workflows/deploy-lockup-linear.yml @@ -3,7 +3,7 @@ name: "Deploy Lockup Linear" env: API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.MNEMONIC }} + MNEMONIC: ${{ secrets.EVM_MNEMONIC }} on: workflow_dispatch: diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml index 2b338e7b7..327229491 100644 --- a/.github/workflows/deploy-nft-descriptor.yml +++ b/.github/workflows/deploy-nft-descriptor.yml @@ -3,7 +3,7 @@ name: "Deploy NFT Descriptor" env: API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.MNEMONIC }} + MNEMONIC: ${{ secrets.EVM_MNEMONIC }} on: workflow_dispatch: From 1f092154a4332ee98f6d4aeb163f4608fc5cc9b7 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Tue, 6 Feb 2024 17:14:21 +0200 Subject: [PATCH 025/132] feat: add a util function to construct the create2 salt (#814) * feat: add a util function to construct the create2 salt build: udpate multi chain script * chore: solhint-disable no-console in Base_Script * docs: improve natspec in constructCreate2Salt chore: remove underscore from function name * test: constructCreate2Salt function * build: set ffi true in test foundry profile --- foundry.toml | 1 + script/Base.s.sol | 30 ++++++- script/DeployDeterministicComptroller.s.sol | 15 +--- script/DeployDeterministicCore.s.sol | 5 +- script/DeployDeterministicCore2.s.sol | 5 +- script/DeployDeterministicCore3.s.sol | 5 +- script/DeployDeterministicLockupDynamic.s.sol | 6 +- script/DeployDeterministicLockupLinear.s.sol | 8 +- script/DeployDeterministicNFTDescriptor.s.sol | 7 +- shell/deploy-multi-chain.sh | 85 +++++++------------ test/utils/BaseScript.t.sol | 23 +++++ 11 files changed, 98 insertions(+), 92 deletions(-) create mode 100644 test/utils/BaseScript.t.sol diff --git a/foundry.toml b/foundry.toml index 0b148369a..0749285f4 100644 --- a/foundry.toml +++ b/foundry.toml @@ -71,6 +71,7 @@ # Test the optimized contracts without re-compiling them [profile.test-optimized] + ffi = true src = "test" [doc] diff --git a/script/Base.s.sol b/script/Base.s.sol index e9f18740e..8e710a6af 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable no-console pragma solidity >=0.8.19 <0.9.0; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; + +import { console2 } from "forge-std/src/console2.sol"; import { Script } from "forge-std/src/Script.sol"; -abstract contract BaseScript is Script { +contract BaseScript is Script { + using Strings for uint256; + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -38,4 +44,26 @@ abstract contract BaseScript is Script { _; vm.stopBroadcast(); } + + /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: + /// https://github.com/Arachnid/deterministic-deployment-proxy + /// + /// Notes: + /// - The salt format is "ChainID , Version ". + /// - The version is obtained from `package.json` using the `ffi` cheatcode: + /// https://book.getfoundry.sh/cheatcodes/ffi + /// - Requires `jq` CLI tool installed: https://jqlang.github.io/jq/ + function constructCreate2Salt() public returns (bytes32) { + string memory chainId = block.chainid.toString(); + string[] memory inputs = new string[](4); + inputs[0] = "jq"; + inputs[1] = "-r"; + inputs[2] = ".version"; + inputs[3] = "./package.json"; + bytes memory result = vm.ffi(inputs); + string memory version = string(result); + string memory create2Salt = string.concat("ChainID ", chainId, ", Version ", version); + console2.log("The CREATE2 salt is \"%s\"", create2Salt); + return bytes32(abi.encodePacked(create2Salt)); + } } diff --git a/script/DeployDeterministicComptroller.s.sol b/script/DeployDeterministicComptroller.s.sol index e609d960c..9c4d8d8eb 100644 --- a/script/DeployDeterministicComptroller.s.sol +++ b/script/DeployDeterministicComptroller.s.sol @@ -8,17 +8,8 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys {SablierV2Comptroller} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicComptroller is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: - /// https://github.com/Arachnid/deterministic-deployment-proxy - function run( - string memory create2Salt, - address initialAdmin - ) - public - virtual - broadcast - returns (SablierV2Comptroller comptroller) - { - comptroller = new SablierV2Comptroller{ salt: bytes32(abi.encodePacked(create2Salt)) }(initialAdmin); + function run(address initialAdmin) public virtual broadcast returns (SablierV2Comptroller comptroller) { + bytes32 salt = constructCreate2Salt(); + comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); } } diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 58d8de483..4603f4c00 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -17,10 +17,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy the contract via a deterministic CREATE2 factory. - /// https://github.com/Arachnid/deterministic-deployment-proxy function run( - string memory create2Salt, address initialAdmin, uint256 maxSegmentCount ) @@ -34,7 +31,7 @@ contract DeployDeterministicCore is BaseScript { SablierV2NFTDescriptor nftDescriptor ) { - bytes32 salt = bytes32(abi.encodePacked(create2Salt)); + bytes32 salt = constructCreate2Salt(); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); lockupDynamic = diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 809dac843..a999ecf76 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -16,10 +16,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy the contract via a deterministic CREATE2 factory. - /// https://github.com/Arachnid/deterministic-deployment-proxy function run( - string memory create2Salt, address initialAdmin, ISablierV2NFTDescriptor nftDescriptor, uint256 maxSegmentCount @@ -33,7 +30,7 @@ contract DeployDeterministicCore2 is BaseScript { SablierV2LockupLinear lockupLinear ) { - bytes32 salt = bytes32(abi.encodePacked(create2Salt)); + bytes32 salt = constructCreate2Salt(); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol index 74ab49c95..0174c712b 100644 --- a/script/DeployDeterministicCore3.s.sol +++ b/script/DeployDeterministicCore3.s.sol @@ -16,10 +16,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore3 is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy the contract via a deterministic CREATE2 factory. - /// https://github.com/Arachnid/deterministic-deployment-proxy function run( - string memory create2Salt, address initialAdmin, ISablierV2Comptroller comptroller, uint256 maxSegmentCount @@ -33,7 +30,7 @@ contract DeployDeterministicCore3 is BaseScript { SablierV2LockupLinear lockupLinear ) { - bytes32 salt = bytes32(abi.encodePacked(create2Salt)); + bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 8c25b4a83..ef58d9b0c 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -10,10 +10,7 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: - /// https://github.com/Arachnid/deterministic-deployment-proxy function run( - string memory create2Salt, address initialAdmin, ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor, @@ -24,7 +21,8 @@ contract DeployDeterministicLockupDynamic is BaseScript { broadcast returns (SablierV2LockupDynamic lockupDynamic) { - lockupDynamic = new SablierV2LockupDynamic{ salt: bytes32(abi.encodePacked(create2Salt)) }( + bytes32 salt = constructCreate2Salt(); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }( initialAdmin, initialComptroller, initialNFTDescriptor, maxSegmentCount ); } diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index 3526a45fb..921429799 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -10,10 +10,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: - /// https://github.com/Arachnid/deterministic-deployment-proxy function run( - string memory create2Salt, address initialAdmin, ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor @@ -23,8 +20,7 @@ contract DeployDeterministicLockupLinear is BaseScript { broadcast returns (SablierV2LockupLinear lockupLinear) { - lockupLinear = new SablierV2LockupLinear{ salt: bytes32(abi.encodePacked(create2Salt)) }( - initialAdmin, initialComptroller, initialNFTDescriptor - ); + bytes32 salt = constructCreate2Salt(); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor); } } diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index f7a348b74..7998d4f28 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -8,9 +8,8 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { - /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: - /// https://github.com/Arachnid/deterministic-deployment-proxy - function run(string memory create2Salt) public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = new SablierV2NFTDescriptor{ salt: bytes32(abi.encodePacked(create2Salt)) }(); + function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + bytes32 salt = constructCreate2Salt(); + nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); } } diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 98def7eca..27456d246 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -86,19 +86,6 @@ export POLYGON_ADMIN="0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6" export SCROLL_ADMIN="0x0F7Ad835235Ede685180A5c611111610813457a9" export SEPOLIA_ADMIN="0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F" -# Declare the chain IDs -ARBITRUM_CHAIN_ID="42161" -ARBITRUM_SEPOLIA_CHAIN_ID="421614" -AVALANCHE_CHAIN_ID="43114" -BASE_CHAIN_ID="8453" -BSC_CHAIN_ID="56" -GNOSIS_CHAIN_ID="100" -MAINNET_CHAIN_ID="1" -OPTIMISM_CHAIN_ID="10" -POLYGON_CHAIN_ID="137" -SCROLL_CHAIN_ID="534352" -SEPOLIA_CHAIN_ID="11155111" - # Flag for broadcast deployment BROADCAST_DEPLOYMENT=false @@ -129,17 +116,17 @@ declare -A chains # define function to initialize all configurations function initialize { - chains["arbitrum"]="$ARBITRUM_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_CHAIN_ID $ARBITRUM_ADMIN $ARBITRUM_COMPTROLLER" - chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_CHAIN_ID $ARBITRUM_SEPOLIA_ADMIN $ARBITRUM_SEPOLIA_COMPTROLLER" - chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_CHAIN_ID $AVALANCHE_ADMIN $AVALANCHE_COMPTROLLER" - chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_CHAIN_ID $BASE_ADMIN $BASE_COMPTROLLER" - chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_CHAIN_ID $BSC_ADMIN $BSC_COMPTROLLER" - chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_CHAIN_ID $GNOSIS_ADMIN $GNOSIS_COMPTROLLER" - chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_CHAIN_ID $MAINNET_ADMIN $MAINNET_COMPTROLLER" - chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_CHAIN_ID $OPTIMISM_ADMIN $OPTIMISM_COMPTROLLER" - chains["polygon"]="$POLYGON_RPC_URL $POLYGONSCAN_API_KEY $POLYGON_CHAIN_ID $POLYGON_ADMIN $POLYGON_COMPTROLLER" - chains["sepolia"]="$SEPOLIA_RPC_URL $ETHERSCAN_API_KEY $SEPOLIA_CHAIN_ID $SEPOLIA_ADMIN $SEPOLIA_COMPTROLLER" - chains["scroll"]="$SCROLL_RPC_URL $SCROLLSCAN_API_KEY $SCROLL_CHAIN_ID $SCROLL_ADMIN $SCROLL_COMPTROLLER" + chains["arbitrum"]="$ARBITRUM_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_ADMIN $ARBITRUM_COMPTROLLER" + chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_ADMIN $ARBITRUM_SEPOLIA_COMPTROLLER" + chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_ADMIN $AVALANCHE_COMPTROLLER" + chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_ADMIN $BASE_COMPTROLLER" + chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_ADMIN $BSC_COMPTROLLER" + chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_ADMIN $GNOSIS_COMPTROLLER" + chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_ADMIN $MAINNET_COMPTROLLER" + chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_ADMIN $OPTIMISM_COMPTROLLER" + chains["polygon"]="$POLYGON_RPC_URL $POLYGONSCAN_API_KEY $POLYGON_ADMIN $POLYGON_COMPTROLLER" + chains["sepolia"]="$SEPOLIA_RPC_URL $ETHERSCAN_API_KEY $SEPOLIA_ADMIN $SEPOLIA_COMPTROLLER" + chains["scroll"]="$SCROLL_RPC_URL $SCROLLSCAN_API_KEY $SCROLL_ADMIN $SCROLL_COMPTROLLER" } # define function to initialize limited configurations @@ -154,18 +141,18 @@ function initialize_interactive { echo -e "3. Enter max segment count: \c" read MAX_SEGMENT_COUNT - # chain id and comptroller only - chains["arbitrum"]="$ARBITRUM_CHAIN_ID $ARBITRUM_COMPTROLLER" - chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_CHAIN_ID $ARBITRUM_SEPOLIA_COMPTROLLER" - chains["avalanche"]="$AVALANCHE_CHAIN_ID $AVALANCHE_COMPTROLLER" - chains["base"]="$BASE_CHAIN_ID $BASE_COMPTROLLER" - chains["bnb_smart_chain"]="$BSC_CHAIN_ID $BSC_COMPTROLLER" - chains["gnosis"]="$GNOSIS_CHAIN_ID $GNOSIS_COMPTROLLER" - chains["mainnet"]="$MAINNET_CHAIN_ID $MAINNET_COMPTROLLER" - chains["optimism"]="$OPTIMISM_CHAIN_ID $OPTIMISM_COMPTROLLER" - chains["polygon"]="$POLYGON_CHAIN_ID $POLYGON_COMPTROLLER" - chains["sepolia"]="$SEPOLIA_CHAIN_ID $SEPOLIA_COMPTROLLER" - chains["scroll"]="$SCROLL_CHAIN_ID $SCROLL_COMPTROLLER" + # Comptroller only + chains["arbitrum"]="$ARBITRUM_COMPTROLLER" + chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_COMPTROLLER" + chains["avalanche"]="$AVALANCHE_COMPTROLLER" + chains["base"]="$BASE_COMPTROLLER" + chains["bnb_smart_chain"]="$BSC_COMPTROLLER" + chains["gnosis"]="$GNOSIS_COMPTROLLER" + chains["mainnet"]="$MAINNET_COMPTROLLER" + chains["optimism"]="$OPTIMISM_COMPTROLLER" + chains["polygon"]="$POLYGON_COMPTROLLER" + chains["sepolia"]="$SEPOLIA_COMPTROLLER" + chains["scroll"]="$SCROLL_COMPTROLLER" } if [ -f .env.deployment ]; then @@ -204,12 +191,6 @@ for ((i=1; i<=$#; i++)); do # Check if '--deterministic' flag is provided in the arguments if [[ ${arg} == "--deterministic" ]]; then - echo -e "\nWhat version is this deployment? (1.1.1 or 1.1.2): \c" - read VERSION - if [[ "${VERSION}" != "1.1.1" && "${VERSION}" != "1.1.2" ]]; then - echo -e "\n${EC}Invalid version. Please enter either 1.1.1 or 1.1.2${NC}" - exit 1 - fi DETERMINISTIC_DEPLOYMENT=true fi @@ -226,10 +207,10 @@ for ((i=1; i<=$#; i++)); do # Print the chains and their Chain IDs for chain in "${sorted_names[@]}"; do - IFS=' ' read -r rpc_url api_key chain_id admin comptroller <<< "${chains[$chain]}" + IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}" - # Print the chain and Chain ID - printf "%-20s %-20s\n" "${chain}" "${chain_id}" + # Print the chain + printf "%-20s %-20s\n" "${chain}" done exit 0 fi @@ -325,10 +306,10 @@ for chain in "${provided_chains[@]}"; do read rpc_url # Get the values from the chains array - IFS=' ' read -r chain_id comptroller <<< "${chains[$chain]}" + IFS=' ' read -r comptroller <<< "${chains[$chain]}" else - # Split the configuration into RPC, API key, Chain ID, admin, and comptroller - IFS=' ' read -r rpc_url api_key chain_id admin comptroller <<< "${chains[$chain]}" + # Split the configuration into RPC, API key, admin, and comptroller + IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}" fi # Declare the deployment command @@ -340,7 +321,7 @@ for chain in "${provided_chains[@]}"; do if [[ ${DETERMINISTIC_DEPLOYMENT} == true ]]; then echo -e "${SC}+${NC} Deterministic address" if [[ ${sol_script} == "" ]]; then - deployment_command+=("script" "script/DeployDeterministicCore3.s.sol") + deployment_command+=("script" "script/DeployDeterministicCore3.s.sol" "--ffi") else deployment_command+=("script" "${sol_script}") fi @@ -352,11 +333,9 @@ for chain in "${provided_chains[@]}"; do # echo removes single quotes #################################################################### if [[ ${READ_ONLY} == true ]]; then - deployment_command+=("--sig" "'run(string,address,address,uint256)'") - deployment_command+=("'ChainID ${chain_id}, Version ${VERSION}'") + deployment_command+=("--sig" "'run(address,address,uint256)'") else - deployment_command+=("--sig" "run(string,address,address,uint256)") - deployment_command+=("ChainID ${chain_id}, Version ${VERSION}") + deployment_command+=("--sig" "run(address,address,uint256)") fi else # Construct the command diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol new file mode 100644 index 000000000..bf9533720 --- /dev/null +++ b/test/utils/BaseScript.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19 <0.9.0; + +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { PRBTest } from "@prb/test/src/PRBTest.sol"; + +import { BaseScript } from "script/Base.s.sol"; + +contract BaseScript_Test is PRBTest { + using Strings for uint256; + + BaseScript internal baseScript = new BaseScript(); + + function test_ConstructCreate2Salt() public { + string memory chainId = block.chainid.toString(); + string memory version = "1.1.2"; + string memory salt = string.concat("ChainID ", chainId, ", Version ", version); + + bytes32 actualSalt = baseScript.constructCreate2Salt(); + bytes32 expectedSalt = bytes32(abi.encodePacked(salt)); + assertEq(actualSalt, expectedSalt, "CREATE2 salt mismatch"); + } +} From 10bc0b774614e933f29ff29523833d330b2c8cce Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 7 Feb 2024 16:29:23 +0200 Subject: [PATCH 026/132] ci: remove deployment workflows --- .github/workflows/deploy-comptroller.yml | 43 ---------------- .github/workflows/deploy-core.yml | 48 ------------------ .github/workflows/deploy-lockup-dynamic.yml | 56 --------------------- .github/workflows/deploy-lockup-linear.yml | 51 ------------------- .github/workflows/deploy-nft-descriptor.yml | 37 -------------- 5 files changed, 235 deletions(-) delete mode 100644 .github/workflows/deploy-comptroller.yml delete mode 100644 .github/workflows/deploy-core.yml delete mode 100644 .github/workflows/deploy-lockup-dynamic.yml delete mode 100644 .github/workflows/deploy-lockup-linear.yml delete mode 100644 .github/workflows/deploy-nft-descriptor.yml diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml deleted file mode 100644 index 2b4f1cd3b..000000000 --- a/.github/workflows/deploy-comptroller.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "Deploy Comptroller" - -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.EVM_MNEMONIC }} - -on: - workflow_dispatch: - inputs: - admin: - default: "0xF3663da48030b6c88535413Fd643aB0B5F3496ff" - description: "Initial contract admin." - required: false - chain: - default: "sepolia" - description: "Chain name as defined in the Foundry config." - required: false - -jobs: - deploy-comptroller: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Deploy the SablierV2Comptroller contract" - run: >- - forge script script/DeployComptroller.s.sol - --broadcast - --rpc-url "${{ inputs.chain }}" - --sig "run(address)" - --verify - -vvvv - "${{ inputs.admin }}" - - - name: "Add workflow summary" - run: | - echo "## Result" >> $GITHUB_STEP_SUMMARY - echo "✅ Done" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml deleted file mode 100644 index f3fb8d5fb..000000000 --- a/.github/workflows/deploy-core.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: "Deploy Core" - -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.EVM_MNEMONIC }} - -on: - workflow_dispatch: - inputs: - admin: - default: "0xF3663da48030b6c88535413Fd643aB0B5F3496ff" - description: "Initial protocol admin." - required: false - chain: - default: "sepolia" - description: "Chain name as defined in the Foundry config." - required: false - max-segment-count: - default: "300" - description: "Maximum number of segments allowed in a stream." - required: false - -jobs: - deploy-core: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Deploy the Sablier V2 Core protocol" - run: >- - forge script script/DeployCore.s.sol - --broadcast - --rpc-url "${{ inputs.chain }}" - --sig "run(address,uint256)" - --verify - "${{ inputs.admin }}" - "${{ inputs.max-segment-count }}" - -vvvv - - - name: "Add workflow summary" - run: | - echo "## Result" >> $GITHUB_STEP_SUMMARY - echo "✅ Done" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml deleted file mode 100644 index 0792d2da8..000000000 --- a/.github/workflows/deploy-lockup-dynamic.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "Deploy Lockup Dynamic" - -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.EVM_MNEMONIC }} - -on: - workflow_dispatch: - inputs: - admin: - default: "0xF3663da48030b6c88535413Fd643aB0B5F3496ff" - description: "Initial contract admin." - required: false - chain: - default: "sepolia" - description: "Chain name as defined in the Foundry config." - required: false - comptroller: - description: "Address of an already deployed comptroller." - required: true - nft-descriptor: - description: "Address of an NFT descriptor contract." - required: true - max-segment-count: - default: "300" - description: "Maximum number of segments allowed in a stream." - required: false - -jobs: - deploy-lockup-dynamic: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Deploy the SablierV2LockupDynamic contract" - run: >- - forge script script/DeployLockupDynamic.s.sol - --broadcast - --rpc-url "${{ inputs.chain }}" - --sig "run(address,address,address,uint256)" - --verify - "${{ inputs.admin }}" - "${{ inputs.comptroller }}" - "${{ inputs.nft-descriptor }}" - "${{ inputs.max-segment-count }}" - -vvvv - - - name: "Add workflow summary" - run: | - echo "## Result" >> $GITHUB_STEP_SUMMARY - echo "✅ Done" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml deleted file mode 100644 index 951dda899..000000000 --- a/.github/workflows/deploy-lockup-linear.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: "Deploy Lockup Linear" - -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.EVM_MNEMONIC }} - -on: - workflow_dispatch: - inputs: - admin: - default: "0xF3663da48030b6c88535413Fd643aB0B5F3496ff" - description: "Initial contract admin." - required: false - chain: - default: "sepolia" - description: "Chain name as defined in the Foundry config." - required: false - comptroller: - description: "Address of an already deployed comptroller." - required: true - nft-descriptor: - description: "Address of an NFT descriptor contract." - required: true - -jobs: - deploy-lockup-linear: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Deploy the SablierV2LockupLinear contract" - run: >- - forge script script/DeployLockupLinear.s.sol - --broadcast - --rpc-url ${{ inputs.chain }} - --sig "run(address,address,address)" - --verify - "${{ inputs.admin }}" - "${{ inputs.comptroller }}" - "${{ inputs.nft-descriptor }}" - -vvvv - - - name: "Add workflow summary" - run: | - echo "## Result" >> $GITHUB_STEP_SUMMARY - echo "✅ Done" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml deleted file mode 100644 index 327229491..000000000 --- a/.github/workflows/deploy-nft-descriptor.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: "Deploy NFT Descriptor" - -env: - API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }} - FOUNDRY_PROFILE: "optimized" - MNEMONIC: ${{ secrets.EVM_MNEMONIC }} - -on: - workflow_dispatch: - inputs: - chain: - default: "sepolia" - description: "Chain name as defined in the Foundry config." - required: false - -jobs: - deploy-nft-descriptor: - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Install Foundry" - uses: "foundry-rs/foundry-toolchain@v1" - - - name: "Deploy the NFT Descriptor" - run: >- - forge script script/DeployNFTDescriptor.s.sol - --broadcast - --rpc-url "${{ inputs.chain }}" - --verify - -vvvv - - - name: "Add workflow summary" - run: | - echo "## Result" >> $GITHUB_STEP_SUMMARY - echo "✅ Done" >> $GITHUB_STEP_SUMMARY From 9ebb59abfdbe3eb1f286ed4e04c849bad51e7113 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 8 Feb 2024 17:37:29 +0200 Subject: [PATCH 027/132] build: set ffi true in default profile --- foundry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/foundry.toml b/foundry.toml index 0749285f4..6d2d04a76 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,6 +2,7 @@ auto_detect_solc = false bytecode_hash = "none" emv_version = "paris" + ffi = true fs_permissions = [{ access = "read", path = "out-optimized" }] gas_reports = [ "SablierV2Comptroller", From 897bca6a1fefedf2cb1059cc48a9f65126fa33bb Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 14 Feb 2024 18:19:18 +0200 Subject: [PATCH 028/132] ci: run fork tests only monday, wednesday and friday --- .github/workflows/ci-fork.yml | 24 ++++++++++++++++++++++++ .github/workflows/ci.yml | 12 ------------ 2 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci-fork.yml diff --git a/.github/workflows/ci-fork.yml b/.github/workflows/ci-fork.yml new file mode 100644 index 000000000..ab463578a --- /dev/null +++ b/.github/workflows/ci-fork.yml @@ -0,0 +1,24 @@ +name: "CI Fork tests" + +on: + schedule: + - cron: "0 3 * * 1,3,5" # at 3:00 AM UTC on Monday, Wednesday and Friday + +jobs: + lint: + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-lint.yml@main" + + build: + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-build.yml@main" + + test-fork: + needs: ["lint", "build"] + secrets: + RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: 100 + foundry-profile: "test-optimized" + fuzz-seed: true + match-path: "test/fork/**/*.sol" + name: "Fork tests" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adeb242da..b538fce79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,18 +52,6 @@ jobs: match-path: "test/invariant/**/*.sol" name: "Invariant tests" - test-fork: - needs: ["lint", "build"] - secrets: - RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} - uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" - with: - foundry-fuzz-runs: 100 - foundry-profile: "test-optimized" - fuzz-seed: true - match-path: "test/fork/**/*.sol" - name: "Fork tests" - coverage: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" From 65d8513c070b240b1cc264036d230771b99d7f79 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:44:09 +0200 Subject: [PATCH 029/132] feat: declare maxCount in BaseScript (#825) --- script/Base.s.sol | 14 ++++++++++++++ script/DeployCore.s.sol | 7 ++----- script/DeployCore2.s.sol | 5 ++--- script/DeployCore3.s.sol | 5 ++--- script/DeployDeterministicCore.s.sol | 8 ++------ script/DeployDeterministicCore2.s.sol | 6 ++---- script/DeployDeterministicCore3.s.sol | 6 ++---- script/DeployDeterministicLockupDynamic.s.sol | 8 +++----- script/DeployLockupDynamic.s.sol | 6 ++---- shell/deploy-multi-chain.sh | 4 ---- 10 files changed, 31 insertions(+), 38 deletions(-) diff --git a/script/Base.s.sol b/script/Base.s.sol index 8e710a6af..c7cb10298 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -10,6 +10,9 @@ import { Script } from "forge-std/src/Script.sol"; contract BaseScript is Script { using Strings for uint256; + /// @dev The Avalanche chain ID. + uint256 internal constant AVALANCHE_CHAIN_ID = 43_114; + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -19,6 +22,10 @@ contract BaseScript is Script { /// @dev The address of the transaction broadcaster. address internal broadcaster; + /// @dev The upper limit on the length of data structures to ensure that transactions stay within the + /// block gas limit. + uint256 internal maxCount; + /// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined. string internal mnemonic; @@ -37,6 +44,13 @@ contract BaseScript is Script { mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC }); (broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 }); } + + // Sets `maxCount` to 300 for Avalanche, and 500 for all other chains. + if (block.chainid == AVALANCHE_CHAIN_ID) { + maxCount = 300; + } else { + maxCount = 500; + } } modifier broadcast() { diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index cb70fa7a1..af004c481 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -15,10 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 3. {SablierV2LockupDynamic} /// 4. {SablierV2LockupLinear} contract DeployCore is BaseScript { - function run( - address initialAdmin, - uint256 maxSegmentCount - ) + function run(address initialAdmin) public virtual broadcast @@ -31,7 +28,7 @@ contract DeployCore is BaseScript { { comptroller = new SablierV2Comptroller(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 3ce985c69..6c5bd2bb5 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -16,8 +16,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployCore2 is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor, - uint256 maxSegmentCount + ISablierV2NFTDescriptor nftDescriptor ) public virtual @@ -29,7 +28,7 @@ contract DeployCore2 is BaseScript { ) { comptroller = new SablierV2Comptroller(initialAdmin); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol index 97381135d..5d71594c6 100644 --- a/script/DeployCore3.s.sol +++ b/script/DeployCore3.s.sol @@ -16,8 +16,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployCore3 is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller comptroller, - uint256 maxSegmentCount + ISablierV2Comptroller comptroller ) public virtual @@ -29,7 +28,7 @@ contract DeployCore3 is BaseScript { ) { nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 4603f4c00..d6c00ad44 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -17,10 +17,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - function run( - address initialAdmin, - uint256 maxSegmentCount - ) + function run(address initialAdmin) public virtual broadcast @@ -34,8 +31,7 @@ contract DeployDeterministicCore is BaseScript { bytes32 salt = constructCreate2Salt(); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index a999ecf76..77d84ad3c 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -18,8 +18,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployDeterministicCore2 is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor, - uint256 maxSegmentCount + ISablierV2NFTDescriptor nftDescriptor ) public virtual @@ -32,8 +31,7 @@ contract DeployDeterministicCore2 is BaseScript { { bytes32 salt = constructCreate2Salt(); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); - lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol index 0174c712b..3335c3a97 100644 --- a/script/DeployDeterministicCore3.s.sol +++ b/script/DeployDeterministicCore3.s.sol @@ -18,8 +18,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployDeterministicCore3 is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller comptroller, - uint256 maxSegmentCount + ISablierV2Comptroller comptroller ) public virtual @@ -32,8 +31,7 @@ contract DeployDeterministicCore3 is BaseScript { { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); } } diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index ef58d9b0c..b57a727e2 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -13,8 +13,7 @@ contract DeployDeterministicLockupDynamic is BaseScript { function run( address initialAdmin, ISablierV2Comptroller initialComptroller, - ISablierV2NFTDescriptor initialNFTDescriptor, - uint256 maxSegmentCount + ISablierV2NFTDescriptor initialNFTDescriptor ) public virtual @@ -22,8 +21,7 @@ contract DeployDeterministicLockupDynamic is BaseScript { returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }( - initialAdmin, initialComptroller, initialNFTDescriptor, maxSegmentCount - ); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); } } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index b27f75396..6e59a05a6 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -11,15 +11,13 @@ contract DeployLockupDynamic is BaseScript { function run( address initialAdmin, ISablierV2Comptroller initialComptroller, - ISablierV2NFTDescriptor initialNFTDescriptor, - uint256 maxSegmentCount + ISablierV2NFTDescriptor initialNFTDescriptor ) public virtual broadcast returns (SablierV2LockupDynamic lockupDynamic) { - lockupDynamic = - new SablierV2LockupDynamic(initialAdmin, initialComptroller, initialNFTDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); } } diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 27456d246..60fa9e561 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -138,9 +138,6 @@ function initialize_interactive { echo -e "2. Enter Etherscan API key: \c" read api_key - echo -e "3. Enter max segment count: \c" - read MAX_SEGMENT_COUNT - # Comptroller only chains["arbitrum"]="$ARBITRUM_COMPTROLLER" chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_COMPTROLLER" @@ -355,7 +352,6 @@ for chain in "${provided_chains[@]}"; do deployment_command+=("${admin}") deployment_command+=("${comptroller}") - deployment_command+=("${MAX_SEGMENT_COUNT}") deployment_command+=("-vvv") # Append additional options if gas price is enabled From 588eddd04fc9e8a1fe52045a68616a4a51777a9c Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:58:40 +0200 Subject: [PATCH 030/132] Completely remove the flash loan logic (#779) * feat: remove flash loan logic test: update tests accordingly docs: remove flash loan reference in README * test: re-add setProtocolFee tests --- .gas-snapshot | 604 +++++++++--------- README.md | 4 - script/Init.s.sol | 14 - src/SablierV2Comptroller.sol | 26 - src/abstracts/SablierV2FlashLoan.sol | 174 ----- src/interfaces/ISablierV2Comptroller.sol | 47 -- .../erc3156/IERC3156FlashBorrower.sol | 17 - .../erc3156/IERC3156FlashLender.sol | 22 - src/libraries/Errors.sol | 16 - test/Base.t.sol | 4 - test/integration/Integration.t.sol | 6 - ...ProtocolFee.t.sol => setProtocolFee.s.sol} | 2 +- .../set-protocol-fee/setProtocolFee.tree | 3 +- .../toggle-flash-asset/toggleFlashAsset.t.sol | 53 -- .../toggle-flash-asset/toggleFlashAsset.tree | 10 - .../flash-loan/flash-fee/flashFee.t.sol | 27 - .../flash-loan/flash-fee/flashFee.tree | 5 - .../flash-loan/flash-loan/flashLoan.t.sol | 145 ----- .../flash-loan/flash-loan/flashLoan.tree | 26 - .../max-flash-loan/maxFlashLoan.t.sol | 25 - .../max-flash-loan/maxFlashLoan.tree | 5 - .../nft-descriptor/generateAccentColor.t.sol | 2 +- .../fuzz/comptroller/setFlashFee.t.sol | 28 - .../fuzz/flash-loan/flashFee.t.sol | 25 - .../fuzz/flash-loan/flashLoan.t.sol | 111 ---- .../fuzz/flash-loan/maxFlashLoan.t.sol | 18 - .../shared/flash-loan/FlashLoan.t.sol | 30 - .../shared/flash-loan/flashLoanFunction.t.sol | 39 -- .../invariant/handlers/ComptrollerHandler.sol | 20 - test/invariant/handlers/FlashLoanHandler.sol | 93 --- .../flash-loan/FaultyFlashLoanReceiver.sol | 26 - test/mocks/flash-loan/FlashLoanMock.sol | 16 - .../flash-loan/GoodFlashLoanReceiver.sol | 26 - .../flash-loan/ReentrantFlashLoanReceiver.sol | 27 - .../comptroller/flash-fee/flashFee.t.sol | 27 - .../comptroller/flash-fee/flashFee.tree | 5 - .../set-flash-fee/setFlashFee.t.sol | 65 -- .../set-flash-fee/setFlashFee.tree | 10 - test/utils/Constants.sol | 1 - test/utils/Defaults.sol | 1 - test/utils/Events.sol | 18 - test/utils/Precompiles.sol | 2 +- 42 files changed, 299 insertions(+), 1526 deletions(-) delete mode 100644 src/abstracts/SablierV2FlashLoan.sol delete mode 100644 src/interfaces/erc3156/IERC3156FlashBorrower.sol delete mode 100644 src/interfaces/erc3156/IERC3156FlashLender.sol rename test/integration/concrete/comptroller/set-protocol-fee/{setProtocolFee.t.sol => setProtocolFee.s.sol} (97%) delete mode 100644 test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.t.sol delete mode 100644 test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.tree delete mode 100644 test/integration/concrete/flash-loan/flash-fee/flashFee.t.sol delete mode 100644 test/integration/concrete/flash-loan/flash-fee/flashFee.tree delete mode 100644 test/integration/concrete/flash-loan/flash-loan/flashLoan.t.sol delete mode 100644 test/integration/concrete/flash-loan/flash-loan/flashLoan.tree delete mode 100644 test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.t.sol delete mode 100644 test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.tree delete mode 100644 test/integration/fuzz/comptroller/setFlashFee.t.sol delete mode 100644 test/integration/fuzz/flash-loan/flashFee.t.sol delete mode 100644 test/integration/fuzz/flash-loan/flashLoan.t.sol delete mode 100644 test/integration/fuzz/flash-loan/maxFlashLoan.t.sol delete mode 100644 test/integration/shared/flash-loan/FlashLoan.t.sol delete mode 100644 test/integration/shared/flash-loan/flashLoanFunction.t.sol delete mode 100644 test/invariant/handlers/FlashLoanHandler.sol delete mode 100644 test/mocks/flash-loan/FaultyFlashLoanReceiver.sol delete mode 100644 test/mocks/flash-loan/FlashLoanMock.sol delete mode 100644 test/mocks/flash-loan/GoodFlashLoanReceiver.sol delete mode 100644 test/mocks/flash-loan/ReentrantFlashLoanReceiver.sol delete mode 100644 test/unit/concrete/comptroller/flash-fee/flashFee.t.sol delete mode 100644 test/unit/concrete/comptroller/flash-fee/flashFee.tree delete mode 100644 test/unit/concrete/comptroller/set-flash-fee/setFlashFee.t.sol delete mode 100644 test/unit/concrete/comptroller/set-flash-fee/setFlashFee.tree diff --git a/.gas-snapshot b/.gas-snapshot index 108269f64..36efba67a 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,254 +1,245 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87490) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78074) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78083) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79288) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87467) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78051) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78060) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79265) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11325) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90245) 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_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19502) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19583) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87747) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78320) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78329) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79516) 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: 833032) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19488) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19569) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 832905) 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: 859296) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32323) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 858977) CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12362) CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78511) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 341157) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 945711) -CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1196571, ~: 1201304) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565457) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 341083) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 945392) +CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1193272, ~: 1199808) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565330) 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: 572656) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32471) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 572337) 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: 245358) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 657145) -CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 797212, ~: 798269) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 386086) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 371238) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97103) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 373429) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 371805) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 245284) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 656826) +CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 796137, ~: 797068) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 386034) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 371186) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97125) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 373377) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 371753) Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76356) Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11321) Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87331) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 67976) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 27022) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 261461) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 452520, ~: 454733) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76862, ~: 76937) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269459) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254587) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 77523) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 256767) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 255154) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 67953) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26999) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 261387) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 453460, ~: 454703) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76876, ~: 77083) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269407) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254535) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 77545) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 256715) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 255102) 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: 185625) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 309321, ~: 310032) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 77016, ~: 77168) -ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319657) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68215) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 27107) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 185551) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 310087, ~: 309980) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 77030, ~: 77168) +ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319605) ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18907) -ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 246434) +ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 246382) ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18915) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5375661) +Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5375705) Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 4181201) -CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380563) -CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4094598, ~: 3552269) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287570) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286462, ~: 286521) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 370909) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 377697) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 47557) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 58099) -CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3941438, ~: 3983919) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282968) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289735) -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, μ: 367857, ~: 375714) -FlashFee_Integration_Concrete_Test:test_FlashFee() (gas: 50968) -FlashFee_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 18626) -FlashFee_Integration_Fuzz_Test:testFuzz_FlashFee(uint256,uint256) (runs: 50, μ: 51835, ~: 52081) -FlashLoanFunction_Integration_Concrete_Test:test_FlashLoan() (gas: 394969) -FlashLoanFunction_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 21603) -FlashLoanFunction_Integration_Fuzz_Test:testFuzz_FlashLoanFunction(uint256,uint128,bytes) (runs: 50, μ: 395010, ~: 399680) +CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380468) +CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4093934, ~: 3551084) +CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287497) +CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286429, ~: 286529) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 370814) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 377602) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 47460) +CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 57967) +CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3960440, ~: 3983787) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282850) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289617) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41034) +CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 51617) +CreateWithRange_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithRange(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256)),uint256) (runs: 50, μ: 368550, ~: 383704) GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13215) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307700) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307626) GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12049) -GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 234445) +GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 234371) GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12035) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 234929) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 234855) GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11392) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 310497) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 310423) GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11682) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 237216) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 237142) GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11678) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 310295) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 310198) GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11538) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 237068) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 236971) GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11546) -GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 309721) +GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 309669) GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13125) -GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 237286) +GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 237189) 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: 72382) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72359) 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_NFTBurned() (gas: 72628) GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 10993) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 362699) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 332639) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 337847) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 337861) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 377426) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 399155) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12045) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 287732) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 257396) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 262604) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 262618) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 298965) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 320726) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12031) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 315199) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 362569) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 332532) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 337717) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 337776) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 377296) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 399025) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 287602) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 257289) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 262474) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 262533) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 298835) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 320596) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 315125) GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13758) -GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 307418) +GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 307344) GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11814) -GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 234179) +GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 234105) GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11816) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 310624) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 310550) GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11823) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 237391) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 237317) GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11831) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 278661) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52024) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 278587) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52001) 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_GetStream() (gas: 34942) +GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 39430) GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14299) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 384601) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 335821) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 384549) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 335769) GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387573, ~: 388098) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337524, ~: 337745) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282096) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262578) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387484, ~: 388043) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337464, ~: 337671) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282044) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262526) GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285296, ~: 285238) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 264308, ~: 264502) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 515747) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 336044) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 327288) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285208, ~: 285164) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 264276, ~: 264428) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 515599) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 335947) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 327214) IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11239) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 372735) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 262953) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 254080) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 372587) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 262856) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 254006) IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11263) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 376124) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 362345) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 330545) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 336315) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 352597) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 376050) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 362248) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 330471) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 336218) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 352545) IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11525) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 297714) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 287436) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 257360) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 263242) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 263777) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 297640) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 287339) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 257286) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 263145) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 263725) IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361783) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326712) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361686) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326638) IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 286836) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 253489) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 286739) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 253415) IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11212) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 327052) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 326978) IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8527) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 253851) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 253777) IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8570) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 327214) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 327140) IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11674) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 515746) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 254035) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 515598) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 253961) IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11739) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 372790) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 375662) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 361859) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 329982) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 335926) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 352082) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 372642) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 375588) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 361762) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 329908) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 335829) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 352030) IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11085) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 297221) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 286912) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 256759) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 262825) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 263224) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 297147) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 286815) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 256685) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 262728) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 263172) IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11106) MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 16961) MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16735) MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 1039755) -MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan() (gas: 175401) -MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan_AssetNotFlashLoanable() (gas: 15248) -MaxFlashLoan_Integration_Fuzz_Test:testFuzz_MaxFlashLoan(uint256) (runs: 50, μ: 175401, ~: 175418) -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: 320169) +ProtocolFees_Integration_Concrete_Test:test_ProtocolFees() (gas: 41122) +ProtocolFees_Integration_Concrete_Test:test_ProtocolFees_ProtocolFeeNotSet() (gas: 9869) +ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 320117) ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10125) -ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246923) +ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246871) ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10111) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361820) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 335782) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 335775) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 342622) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375571) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 398663) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523373) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11099) -RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 45465, ~: 30742) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 286869) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 262546) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 262669) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 264156) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297126) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 320250) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 380366) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11110) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30817, ~: 30858) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 694189) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 687264) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 292481) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 692393) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 687871) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361690) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 335675) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 335645) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 342492) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375464) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 398523) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523192) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11066) +RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 48183, ~: 63495) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 286739) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 262439) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 262539) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 264026) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297019) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 320110) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 380185) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11077) +RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30877, ~: 30917) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 693967) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 687042) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 292407) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 692171) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 687649) Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11567) Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87318) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68280) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24692) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 649669) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 481487) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 474530) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 219327) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 479667) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 475137) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68257) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24669) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 649447) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 481265) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 474308) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 219253) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 479445) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 474915) 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: 436859) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68541) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24799) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 436637) 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) @@ -257,157 +248,152 @@ SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 6 SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13222) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 625096) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 12399) -SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 311753) +SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 214569) SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23283) -SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 311750) +SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 214566) SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23280) -SetFlashFee_Integration_Fuzz_Test:testFuzz_SetFlashFee(uint256) (runs: 50, μ: 37712, ~: 39448) SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6551561) SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2301931) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6550197) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2300372) -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, μ: 43103, ~: 43074) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6550746) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2300992) +SetProtocolFee_Integration_Fuzz_Test:testFuzz_SetProtocolFee(uint256) (runs: 50, μ: 42999, ~: 42942) StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11651) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 352719) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 362484) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 336527) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 330626) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 376298) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 352645) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 362387) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 336430) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 330552) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 376224) StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11681) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 263275) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 287551) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 263440) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 257417) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 297871) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 263201) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 287454) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 263343) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 257343) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 297797) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11319) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestone1st() (gas: 45903) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestoneNot1st() (gas: 50746) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 256899) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 256802) 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: 68614) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68591) 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: 87731) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116269) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3515843, ~: 3102346) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3963864, ~: 4082808) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 275280, ~: 268771) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11349) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 26236) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26601) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87753) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116291) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3517521, ~: 3128319) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3967659, ~: 4100727) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 274652, ~: 268659) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11316) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 26225) 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, μ: 232550, ~: 232497) -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, μ: 237703, ~: 239647) -ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset() (gas: 31848) -ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset_FlagNotEnabled() (gas: 41868) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 27110) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68821) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20272) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26632) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 78511) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 107015) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 232606, ~: 233276) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 27328, ~: 27604) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 237475, ~: 239593) 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: 314151) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 326457) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 240338) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 253182) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 314077) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 326383) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 240264) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 253108) WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12048) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 364415) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 327602) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 364341) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 327528) WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12069) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 289206) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 254379) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75301) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 289132) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 254305) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75278) WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14165) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 265000) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 158508) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100445) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 136366, ~: 155717) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75583) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 264926) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 158530) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100422) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 137956, ~: 155649) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75560) WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14179) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189268) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 111578) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100775) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 101446, ~: 109924) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 134996) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80178) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117466, ~: 120596) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82778, ~: 82960) -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, μ: 73602, ~: 73703) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189194) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 111600) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100752) +WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 99586, ~: 109924) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 135018) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80155) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117353, ~: 120534) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82847, ~: 82960) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 74513) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80471) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 73547, ~: 73702) WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83094, ~: 83276) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73755) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73732) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21033) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124543) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83228) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1830075) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124565) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83205) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1829631) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9112) -WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2744527, ~: 2744738) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 74018) +WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2743359, ~: 2743632) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73995) 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: 1263872) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 105152) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83468) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1263428) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9165) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1773301, ~: 1773175) +WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1772371, ~: 1772218) Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19930) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67757) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 385016) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112705) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81264) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72522) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 362691) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122619) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 390024) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 363246) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 382203) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 124033, ~: 98708) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145420, ~: 145420) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3963949, ~: 3999433) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160726, ~: 160927) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67734) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 384964) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112727) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81286) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72499) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 362639) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122641) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 389972) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 363194) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 382151) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 125250, ~: 98709) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145442, ~: 145442) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3959980, ~: 3999315) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160679, ~: 160866) 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: 268373) -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: 259672) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 75746) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 273408) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 260227) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 292836) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 99421, ~: 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, μ: 141225, ~: 141111) +Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67997) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 268321) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 93114) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 61662) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72696) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 259620) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 75768) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 273356) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 260175) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 292784) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 99363, ~: 99269) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 112233, ~: 112233) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 141175, ~: 141030) WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12045) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 378069) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 347594) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 337199) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 363614) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 333948) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 340171) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 378411) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 400456) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 332901, ~: 320879) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 301928, ~: 300161) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12076) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 253600) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 263471) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 288644) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 258672) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 265025) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 299992) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 322002) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 287022) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 461540, ~: 460821) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263665, ~: 263941) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 437724, ~: 436534) \ No newline at end of file +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 377995) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 347520) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 337125) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 363517) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 333874) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 340074) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 378359) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 400382) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 334198, ~: 351909) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 296030, ~: 289610) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12043) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 253526) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 263386) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 288514) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 258565) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 264895) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 299907) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 321862) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 286937) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 461607, ~: 462240) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263604, ~: 263867) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 437554, ~: 438494) \ No newline at end of file diff --git a/README.md b/README.md index 84c7526ea..55b3785f1 100644 --- a/README.md +++ b/README.md @@ -104,10 +104,6 @@ it is explained in depth [here](https://github.com/sablier-labs/v2-core/wiki/Tes The list of all deployment addresses can be found [here](https://docs.sablier.com). For guidance on the deploy scripts, see the [Deployments wiki](https://github.com/sablier-labs/v2-core/wiki/Deployments). -It is worth noting that not every file in this repository is included in the current deployments. For instance, the -`SablierV2FlashLoan` abstract is not inherited by any contract on the `main` branch, but we have kept it in version -control because we may decide to use it in the future. - ## Security The codebase has undergone rigorous audits by leading security experts from Cantina, as well as independent auditors. diff --git a/script/Init.s.sol b/script/Init.s.sol index 8a99762ac..f3169f902 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -7,7 +7,6 @@ import { ud60x18 } from "@prb/math/src/UD60x18.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"; @@ -21,7 +20,6 @@ interface IERC20Mint { /// @notice Initializes the protocol by setting up the comptroller and creating some streams. contract Init is BaseScript { function run( - ISablierV2Comptroller comptroller, ISablierV2LockupLinear lockupLinear, ISablierV2LockupDynamic lockupDynamic, IERC20 asset @@ -32,18 +30,6 @@ contract Init is BaseScript { address sender = broadcaster; address recipient = vm.addr(vm.deriveKey({ mnemonic: mnemonic, index: 1 })); - /*////////////////////////////////////////////////////////////////////////// - COMPTROLLER - //////////////////////////////////////////////////////////////////////////*/ - - // Enable the ERC-20 asset for flash loaning. - if (!comptroller.isFlashAsset(asset)) { - comptroller.toggleFlashAsset(asset); - } - - // Set the flash fee to 0.05%. - comptroller.setFlashFee({ newFlashFee: ud60x18(0.0005e18) }); - /*////////////////////////////////////////////////////////////////////////// LOCKUP-LINEAR //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/SablierV2Comptroller.sol b/src/SablierV2Comptroller.sol index 2c7390980..696866d0d 100644 --- a/src/SablierV2Comptroller.sol +++ b/src/SablierV2Comptroller.sol @@ -36,12 +36,6 @@ contract SablierV2Comptroller is PUBLIC STORAGE //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Comptroller - UD60x18 public override flashFee; - - /// @inheritdoc ISablierV2Comptroller - mapping(IERC20 asset => bool supported) public override isFlashAsset; - /// @inheritdoc ISablierV2Comptroller mapping(IERC20 asset => UD60x18 fee) public override protocolFees; @@ -60,16 +54,6 @@ contract SablierV2Comptroller is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Comptroller - function setFlashFee(UD60x18 newFlashFee) external override onlyAdmin { - // Effects: set the new flash fee. - UD60x18 oldFlashFee = flashFee; - flashFee = newFlashFee; - - // Log the change of the flash fee. - emit ISablierV2Comptroller.SetFlashFee({ admin: msg.sender, oldFlashFee: oldFlashFee, newFlashFee: newFlashFee }); - } - /// @inheritdoc ISablierV2Comptroller function setProtocolFee(IERC20 asset, UD60x18 newProtocolFee) external override onlyAdmin { // Effects: set the new global fee. @@ -84,14 +68,4 @@ contract SablierV2Comptroller is newProtocolFee: newProtocolFee }); } - - /// @inheritdoc ISablierV2Comptroller - function toggleFlashAsset(IERC20 asset) external override onlyAdmin { - // Effects: enable the ERC-20 asset for flash loaning. - bool oldFlag = isFlashAsset[asset]; - isFlashAsset[asset] = !oldFlag; - - // Log the change of the flash asset flag. - emit ISablierV2Comptroller.ToggleFlashAsset({ admin: msg.sender, asset: asset, newFlag: !oldFlag }); - } } diff --git a/src/abstracts/SablierV2FlashLoan.sol b/src/abstracts/SablierV2FlashLoan.sol deleted file mode 100644 index 2b2002f74..000000000 --- a/src/abstracts/SablierV2FlashLoan.sol +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { ud } from "@prb/math/src/UD60x18.sol"; - -import { IERC3156FlashBorrower } from "../interfaces/erc3156/IERC3156FlashBorrower.sol"; -import { IERC3156FlashLender } from "../interfaces/erc3156/IERC3156FlashLender.sol"; -import { Errors } from "../libraries/Errors.sol"; -import { SablierV2Base } from "./SablierV2Base.sol"; - -/// @title SablierV2FlashLoan -/// @notice This contract implements the ERC-3156 standard to enable flash loans. -/// @dev See https://eips.ethereum.org/EIPS/eip-3156. -abstract contract SablierV2FlashLoan is - IERC3156FlashLender, // 0 inherited components - SablierV2Base // 4 inherited components -{ - using SafeERC20 for IERC20; - - /*////////////////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Emitted when a flash loan is executed. - /// @param initiator The address of the flash loan initiator. - /// @param receiver The address of the flash borrower. - /// @param asset The address of the ERC-20 asset that has been flash loaned. - /// @param amount The amount of `asset` flash loaned. - /// @param feeAmount The fee amount of `asset` charged by the protocol. - /// @param data The data passed to the flash borrower. - event FlashLoan( - address indexed initiator, - IERC3156FlashBorrower indexed receiver, - IERC20 indexed asset, - uint256 amount, - uint256 feeAmount, - bytes data - ); - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL CONSTANTS - //////////////////////////////////////////////////////////////////////////*/ - - bytes32 internal constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan"); - - /*////////////////////////////////////////////////////////////////////////// - CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice The amount of fees to charge for a hypothetical flash loan amount. - /// - /// @dev You might notice a bit of a terminology clash here, since the ERC-3156 standard refers to the "flash fee" - /// as an amount, whereas the flash fee retrieved from the comptroller is a percentage. Throughout the code base, - /// the "amount" suffix is typically appended to variables that represent amounts, but, in this context, the name - /// must be kept unchanged to comply with the ERC. - /// - /// Requirements: - /// - The ERC-20 asset must be flash loanable. - /// - /// @param asset The ERC-20 asset to flash loan. - /// @param amount The amount of `asset` flash loaned. - /// @return fee The amount of `asset` to charge for the loan on top of the returned principal. - function flashFee(address asset, uint256 amount) public view override returns (uint256 fee) { - // Checks: the ERC-20 asset is flash loanable. - if (!comptroller.isFlashAsset(IERC20(asset))) { - revert Errors.SablierV2FlashLoan_AssetNotFlashLoanable(IERC20(asset)); - } - - // Calculate the flash fee. - fee = ud(amount).mul(comptroller.flashFee()).intoUint256(); - } - - /// @notice The amount of ERC-20 assets available for flash loan. - /// @dev If the ERC-20 asset is not flash loanable, this function returns zero. - /// @param asset The address of the ERC-20 asset to query. - /// @return amount The amount of `asset` that can be flash loaned. - function maxFlashLoan(address asset) external view override returns (uint256 amount) { - // The default value is zero, so it doesn't have to be explicitly set. - if (comptroller.isFlashAsset(IERC20(asset))) { - amount = IERC20(asset).balanceOf(address(this)); - } - } - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Allows smart contracts to access the entire liquidity of the Sablier V2 contract within one - /// transaction as long as the principal plus a flash fee is returned. - /// - /// @dev Emits a {FlashLoan} event. - /// - /// Requirements: - /// - Must not be delegate called. - /// - Refer to the requirements in {flashFee}. - /// - `amount` must be less than 2^128. - /// - `fee` must be less than 2^128. - /// - `amount` must not exceed the liquidity available for `asset`. - /// - `msg.sender` must allow this contract to spend at least `amount + fee` assets. - /// - `receiver` implementation of {IERC3156FlashBorrower.onFlashLoan} must return `CALLBACK_SUCCESS`. - /// - /// @param receiver The receiver of the flash loaned assets, and the receiver of the callback. - /// @param asset The address of the ERC-20 asset to use for flash borrowing. - /// @param amount The amount of `asset` to flash loan. - /// @param data Arbitrary data structure, intended to contain user-defined parameters. - /// @return success `true` on success. - function flashLoan( - IERC3156FlashBorrower receiver, - address asset, - uint256 amount, - bytes calldata data - ) - external - override - noDelegateCall - returns (bool success) - { - // Checks: the amount is less than 2^128. This prevents the below calculations from overflowing. - if (amount > type(uint128).max) { - revert Errors.SablierV2FlashLoan_AmountTooHigh(amount); - } - - // Calculate the flash fee. This also checks that the ERC-20 asset is flash loanable. - uint256 fee = flashFee(asset, amount); - - // Checks: the calculated fee is less than 2^128. This check can fail only when the comptroller flash fee - // is set to an abnormally high value. - if (fee > type(uint128).max) { - revert Errors.SablierV2FlashLoan_CalculatedFeeTooHigh(fee); - } - - // Interactions: perform the ERC-20 transfer to flash loan the assets to the borrower. - IERC20(asset).safeTransfer({ to: address(receiver), value: amount }); - - // Interactions: perform the borrower callback. - bytes32 response = - receiver.onFlashLoan({ initiator: msg.sender, asset: asset, amount: amount, fee: fee, data: data }); - - // Checks: the response matches the expected callback success hash. - if (response != CALLBACK_SUCCESS) { - revert Errors.SablierV2FlashLoan_FlashBorrowFail(); - } - - uint256 returnAmount; - - // Using unchecked arithmetic because the checks above prevent these calculations from overflowing. - unchecked { - // Effects: record the flash fee amount in the protocol revenues. The casting to uint128 is safe due - // to the check at the start of the function. - protocolRevenues[IERC20(asset)] = protocolRevenues[IERC20(asset)] + uint128(fee); - - // Calculate the amount that the borrower must return. - returnAmount = amount + fee; - } - - // Interactions: perform the ERC-20 transfer to get the principal back plus the fee. - IERC20(asset).safeTransferFrom({ from: address(receiver), to: address(this), value: returnAmount }); - - // Log the flash loan. - emit FlashLoan({ - initiator: msg.sender, - receiver: receiver, - asset: IERC20(asset), - amount: amount, - feeAmount: fee, - data: data - }); - - // Set the success flag. - success = true; - } -} diff --git a/src/interfaces/ISablierV2Comptroller.sol b/src/interfaces/ISablierV2Comptroller.sol index a6a471530..d7b779d69 100644 --- a/src/interfaces/ISablierV2Comptroller.sol +++ b/src/interfaces/ISablierV2Comptroller.sol @@ -14,12 +14,6 @@ interface ISablierV2Comptroller is IAdminable { EVENTS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Emitted when the admin sets a new flash fee. - /// @param admin The address of the contract admin. - /// @param oldFlashFee The old flash fee, denoted as a fixed-point number. - /// @param newFlashFee The new flash fee, denoted as a fixed-point number. - event SetFlashFee(address indexed admin, UD60x18 oldFlashFee, UD60x18 newFlashFee); - /// @notice Emitted when the admin sets a new protocol fee for the provided ERC-20 asset. /// @param admin The address of the contract admin. /// @param asset The contract address of the ERC-20 asset the new protocol fee has been set for. @@ -27,28 +21,10 @@ interface ISablierV2Comptroller is IAdminable { /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number. event SetProtocolFee(address indexed admin, IERC20 indexed asset, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); - /// @notice Emitted when the admin enables or disables an ERC-20 asset for flash loaning. - /// @param admin The address of the contract admin. - /// @param asset The contract address of the ERC-20 asset to toggle. - /// @param newFlag Whether the ERC-20 asset can be flash loaned. - event ToggleFlashAsset(address indexed admin, IERC20 indexed asset, bool newFlag); - /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the global flash fee, denoted as a fixed-point number where 1e18 is 100%. - /// - /// @dev Notes: - /// - This fee represents a percentage, not an amount. Do not confuse it with {IERC3156FlashLender.flashFee}, - /// which calculates the fee amount for a specified flash loan amount. - /// - Unlike the protocol fee, this is a global fee applied to all flash loans, not a per-asset fee. - function flashFee() external view returns (UD60x18 fee); - - /// @notice Retrieves a flag indicating whether the provided ERC-20 asset can be flash loaned. - /// @param token The contract address of the ERC-20 asset to check. - function isFlashAsset(IERC20 token) external view returns (bool result); - /// @notice Retrieves the protocol fee for all streams created with the provided ERC-20 asset. /// @param asset The contract address of the ERC-20 asset to query. /// @return fee The protocol fee denoted as a fixed-point number where 1e18 is 100%. @@ -58,19 +34,6 @@ interface ISablierV2Comptroller is IAdminable { NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Updates the flash fee charged on all flash loans made with any ERC-20 asset. - /// - /// @dev Emits a {SetFlashFee} event. - /// - /// Notes: - /// - Does not revert if the fee is the same. - /// - /// Requirements: - /// - `msg.sender` must be the contract admin. - /// - /// @param newFlashFee The new flash fee to set, denoted as a fixed-point number where 1e18 is 100%. - function setFlashFee(UD60x18 newFlashFee) external; - /// @notice Sets a new protocol fee that will be charged on all streams created with the provided ERC-20 asset. /// /// @dev Emits a {SetProtocolFee} event. @@ -86,14 +49,4 @@ interface ISablierV2Comptroller is IAdminable { /// @param asset The contract address of the ERC-20 asset to update the fee for. /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number where 1e18 is 100%. function setProtocolFee(IERC20 asset, UD60x18 newProtocolFee) external; - - /// @notice Toggles the flash loanability of an ERC-20 asset. - /// - /// @dev Emits a {ToggleFlashAsset} event. - /// - /// Requirements: - /// - `msg.sender` must be the admin. - /// - /// @param asset The address of the ERC-20 asset to toggle. - function toggleFlashAsset(IERC20 asset) external; } diff --git a/src/interfaces/erc3156/IERC3156FlashBorrower.sol b/src/interfaces/erc3156/IERC3156FlashBorrower.sol deleted file mode 100644 index d065ba3c3..000000000 --- a/src/interfaces/erc3156/IERC3156FlashBorrower.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -/// @title IERC3156FlashBorrower -/// @notice Interface for ERC-3156 flash borrowers. -/// @dev See https://eips.ethereum.org/EIPS/eip-3156. -interface IERC3156FlashBorrower { - function onFlashLoan( - address initiator, - address asset, - uint256 amount, - uint256 fee, - bytes calldata data - ) - external - returns (bytes32); -} diff --git a/src/interfaces/erc3156/IERC3156FlashLender.sol b/src/interfaces/erc3156/IERC3156FlashLender.sol deleted file mode 100644 index bfecc2757..000000000 --- a/src/interfaces/erc3156/IERC3156FlashLender.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -import { IERC3156FlashBorrower } from "./IERC3156FlashBorrower.sol"; - -/// @title IERC3156FlashLender -/// @notice Interface for ERC-3156 flash lenders. -/// @dev See https://eips.ethereum.org/EIPS/eip-3156. -interface IERC3156FlashLender { - function maxFlashLoan(address asset) external view returns (uint256); - - function flashFee(address asset, uint256 amount) external view returns (uint256); - - function flashLoan( - IERC3156FlashBorrower receiver, - address asset, - uint256 amount, - bytes calldata data - ) - external - returns (bool); -} diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 147cf9d1a..4332ab068 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -25,22 +25,6 @@ library Errors { /// @notice Thrown when trying to claim protocol revenues for an asset with no accrued revenues. error SablierV2Base_NoProtocolRevenues(IERC20 asset); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-FLASH-LOAN - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Thrown when trying to flash loan an unsupported asset. - error SablierV2FlashLoan_AssetNotFlashLoanable(IERC20 asset); - - /// @notice Thrown when trying to flash loan an amount greater than or equal to 2^128. - error SablierV2FlashLoan_AmountTooHigh(uint256 amount); - - /// @notice Thrown when the calculated fee during a flash loan is greater than or equal to 2^128. - error SablierV2FlashLoan_CalculatedFeeTooHigh(uint256 amount); - - /// @notice Thrown when the callback to the flash borrower fails. - error SablierV2FlashLoan_FlashBorrowFail(); - /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/Base.t.sol b/test/Base.t.sol index b735e2f5f..7d24c7ba1 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -14,7 +14,6 @@ import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; -import { GoodFlashLoanReceiver } from "./mocks/flash-loan/GoodFlashLoanReceiver.sol"; import { Noop } from "./mocks/Noop.sol"; import { GoodRecipient } from "./mocks/hooks/GoodRecipient.sol"; import { Assertions } from "./utils/Assertions.sol"; @@ -41,7 +40,6 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi ISablierV2Comptroller internal comptroller; ERC20 internal dai; Defaults internal defaults; - GoodFlashLoanReceiver internal goodFlashLoanReceiver; GoodRecipient internal goodRecipient; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; @@ -56,14 +54,12 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi function setUp() public virtual { // Deploy the base test contracts. dai = new ERC20("Dai Stablecoin", "DAI"); - goodFlashLoanReceiver = new GoodFlashLoanReceiver(); goodRecipient = new GoodRecipient(); noop = new Noop(); usdt = new ERC20MissingReturn("Tether USD", "USDT", 6); // Label the base test contracts. vm.label({ account: address(dai), newLabel: "DAI" }); - vm.label({ account: address(goodFlashLoanReceiver), newLabel: "Good Flash Loan Receiver" }); vm.label({ account: address(goodRecipient), newLabel: "Good Recipient" }); vm.label({ account: address(nftDescriptor), newLabel: "NFT Descriptor" }); vm.label({ account: address(noop), newLabel: "Noop" }); diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index 2e0c62ab9..bdcd271d8 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -4,8 +4,6 @@ pragma solidity >=0.8.19 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { Base_Test } from "../Base.t.sol"; -import { FaultyFlashLoanReceiver } from "../mocks/flash-loan/FaultyFlashLoanReceiver.sol"; -import { ReentrantFlashLoanReceiver } from "../mocks/flash-loan/ReentrantFlashLoanReceiver.sol"; import { ReentrantRecipient } from "../mocks/hooks/ReentrantRecipient.sol"; import { RevertingRecipient } from "../mocks/hooks/RevertingRecipient.sol"; @@ -15,8 +13,6 @@ abstract contract Integration_Test is Base_Test { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - FaultyFlashLoanReceiver internal faultyFlashLoanReceiver = new FaultyFlashLoanReceiver(); - ReentrantFlashLoanReceiver internal reentrantFlashLoanReceiver = new ReentrantFlashLoanReceiver(); ReentrantRecipient internal reentrantRecipient = new ReentrantRecipient(); RevertingRecipient internal revertingRecipient = new RevertingRecipient(); @@ -46,8 +42,6 @@ abstract contract Integration_Test is Base_Test { /// @dev Labels the most relevant contracts. function labelContracts() internal { - vm.label({ account: address(faultyFlashLoanReceiver), newLabel: "Faulty Flash Loan Receiver" }); - vm.label({ account: address(reentrantFlashLoanReceiver), newLabel: "Reentrant Flash Loan Receiver" }); vm.label({ account: address(reentrantRecipient), newLabel: "Reentrant Lockup Recipient" }); vm.label({ account: address(revertingRecipient), newLabel: "Reverting Lockup Recipient" }); } diff --git a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.t.sol b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol similarity index 97% rename from test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.t.sol rename to test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol index 91944a606..bf16f79ee 100644 --- a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.t.sol +++ b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol @@ -41,7 +41,7 @@ contract SetProtocolFee_Integration_Concrete_Test is Integration_Test { } function test_SetProtocolFee() external whenCallerAdmin whenNewFee { - UD60x18 newProtocolFee = defaults.FLASH_FEE(); + UD60x18 newProtocolFee = defaults.PROTOCOL_FEE(); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(comptroller) }); diff --git a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree index 7bd610ee8..ed8ffcc23 100644 --- a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree +++ b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree @@ -7,5 +7,4 @@ setProtocolFee.t.sol │ └── it should emit a {SetProtocolFee} event └── when the new protocol fee is not the same as the current protocol fee ├── it should set the new protocol fee - └── it should emit a {SetProtocolFee} event - + └── it should emit a {SetProtocolFee} event \ No newline at end of file diff --git a/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.t.sol b/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.t.sol deleted file mode 100644 index 98ede2015..000000000 --- a/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.t.sol +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { Errors } from "src/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -contract ToggleFlashAsset_Integration_Concrete_Test is Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - comptroller.toggleFlashAsset(dai); - } - - /// @dev The admin is the default caller in the comptroller tests. - modifier whenCallerAdmin() { - _; - } - - function test_ToggleFlashAsset_FlagNotEnabled() external whenCallerAdmin { - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit ToggleFlashAsset({ admin: users.admin, asset: dai, newFlag: true }); - - // Toggle the flash asset. - comptroller.toggleFlashAsset(dai); - - // Assert that the flash asset has been toggled. - bool isFlashAsset = comptroller.isFlashAsset(dai); - assertTrue(isFlashAsset, "isFlashAsset"); - } - - modifier givenFlagEnabled() { - comptroller.toggleFlashAsset(dai); - _; - } - - function test_ToggleFlashAsset() external whenCallerAdmin givenFlagEnabled { - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit ToggleFlashAsset({ admin: users.admin, asset: dai, newFlag: false }); - - // Toggle the flash asset. - comptroller.toggleFlashAsset(dai); - - // Assert that the flash asset has been toggled. - bool isFlashAsset = comptroller.isFlashAsset(dai); - assertFalse(isFlashAsset, "isFlashAsset"); - } -} diff --git a/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.tree b/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.tree deleted file mode 100644 index e6184a843..000000000 --- a/test/integration/concrete/comptroller/toggle-flash-asset/toggleFlashAsset.tree +++ /dev/null @@ -1,10 +0,0 @@ -toggleFlashAsset.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── given the flag is not enabled - │ ├── it should toggle the flash asset - │ └── it should emit a {ToggleFlashAsset} event - └── given the flag is enabled - ├── it should toggle the flash asset - └── it should emit a {ToggleFlashAsset} event diff --git a/test/integration/concrete/flash-loan/flash-fee/flashFee.t.sol b/test/integration/concrete/flash-loan/flash-fee/flashFee.t.sol deleted file mode 100644 index f7eaf9f79..000000000 --- a/test/integration/concrete/flash-loan/flash-fee/flashFee.t.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { ud } from "@prb/math/src/UD60x18.sol"; - -import { Errors } from "src/libraries/Errors.sol"; - -import { FlashLoan_Integration_Shared_Test } from "../../../shared/flash-loan/FlashLoan.t.sol"; - -contract FlashFee_Integration_Concrete_Test is FlashLoan_Integration_Shared_Test { - function test_RevertGiven_AssetNotFlashLoanable() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_AssetNotFlashLoanable.selector, dai)); - flashLoan.flashFee({ asset: address(dai), amount: 0 }); - } - - modifier givenAssetFlashLoanable() { - comptroller.toggleFlashAsset(dai); - _; - } - - function test_FlashFee() external givenAssetFlashLoanable { - uint256 amount = 782.23e18; - uint256 actualFlashFee = flashLoan.flashFee({ asset: address(dai), amount: amount }); - uint256 expectedFlashFee = ud(amount).mul(defaults.FLASH_FEE()).intoUint256(); - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } -} diff --git a/test/integration/concrete/flash-loan/flash-fee/flashFee.tree b/test/integration/concrete/flash-loan/flash-fee/flashFee.tree deleted file mode 100644 index 106525e37..000000000 --- a/test/integration/concrete/flash-loan/flash-fee/flashFee.tree +++ /dev/null @@ -1,5 +0,0 @@ -flashFee.t.sol -├── given the asset is not flash loanable -│ └── it should revert -└── given the asset is flash loanable - └── it should return the correct flash fee diff --git a/test/integration/concrete/flash-loan/flash-loan/flashLoan.t.sol b/test/integration/concrete/flash-loan/flash-loan/flashLoan.t.sol deleted file mode 100644 index 6f67dcf6b..000000000 --- a/test/integration/concrete/flash-loan/flash-loan/flashLoan.t.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; - -import { ud } from "@prb/math/src/UD60x18.sol"; - -import { IERC3156FlashLender } from "src/interfaces/erc3156/IERC3156FlashLender.sol"; -import { Errors } from "src/libraries/Errors.sol"; - -import { FlashLoanFunction_Integration_Shared_Test } from "../../../shared/flash-loan/flashLoanFunction.t.sol"; - -contract FlashLoanFunction_Integration_Concrete_Test is FlashLoanFunction_Integration_Shared_Test { - function setUp() public virtual override { - FlashLoanFunction_Integration_Shared_Test.setUp(); - } - - function test_RevertWhen_DelegateCalled() external { - bytes memory callData = - abi.encodeCall(IERC3156FlashLender.flashLoan, (goodFlashLoanReceiver, address(dai), 0, bytes(""))); - (bool success, bytes memory returnData) = address(flashLoan).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); - } - - function test_RevertWhen_AmountTooHigh() external whenNotDelegateCalled { - uint256 amount = uint256(MAX_UINT128) + 1; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_AmountTooHigh.selector, amount)); - flashLoan.flashLoan({ receiver: goodFlashLoanReceiver, asset: address(dai), amount: amount, data: bytes("") }); - } - - function test_RevertGiven_AssetNotFlashLoanable() external whenNotDelegateCalled whenAmountNotTooHigh { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_AssetNotFlashLoanable.selector, dai)); - flashLoan.flashLoan({ receiver: goodFlashLoanReceiver, asset: address(dai), amount: 0, data: bytes("") }); - } - - function test_RevertWhen_CalculatedFeeTooHigh() - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - { - // Set the comptroller flash fee so that the calculated fee ends up being greater than 2^128. - comptroller.setFlashFee({ newFlashFee: ud(1.1e18) }); - - uint256 fee = flashLoan.flashFee({ asset: address(dai), amount: MAX_UINT128 }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_CalculatedFeeTooHigh.selector, fee)); - flashLoan.flashLoan({ - receiver: goodFlashLoanReceiver, - asset: address(dai), - amount: MAX_UINT128, - data: bytes("") - }); - } - - function test_RevertWhen_BorrowFailed() - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - whenCalculatedFeeNotTooHigh - { - deal({ token: address(dai), to: address(flashLoan), give: LIQUIDITY_AMOUNT }); - vm.expectRevert(Errors.SablierV2FlashLoan_FlashBorrowFail.selector); - flashLoan.flashLoan({ - receiver: faultyFlashLoanReceiver, - asset: address(dai), - amount: LIQUIDITY_AMOUNT, - data: bytes("") - }); - } - - function test_RevertWhen_Reentrancy() - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - whenCalculatedFeeNotTooHigh - whenBorrowDoesNotFail - { - uint256 amount = 100e18; - deal({ token: address(dai), to: address(flashLoan), give: amount * 2 }); - vm.expectRevert("ERC20: transfer amount exceeds balance"); - flashLoan.flashLoan({ - receiver: reentrantFlashLoanReceiver, - asset: address(dai), - amount: LIQUIDITY_AMOUNT / 4, - data: bytes("") - }); - } - - function test_FlashLoan() - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - whenCalculatedFeeNotTooHigh - whenBorrowDoesNotFail - whenNoReentrancy - { - // Mint the liquidity amount to the contract. - deal({ token: address(dai), to: address(flashLoan), give: LIQUIDITY_AMOUNT }); - - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = flashLoan.protocolRevenues(dai); - - // Load the flash fee. - uint256 fee = flashLoan.flashFee({ asset: address(dai), amount: LIQUIDITY_AMOUNT }); - - // Mint the flash fee to the receiver so that they can repay the flash loan. - deal({ token: address(dai), to: address(goodFlashLoanReceiver), give: fee }); - - // Expect `amount` of assets to be transferred to the receiver. - expectCallToTransfer({ to: address(goodFlashLoanReceiver), amount: LIQUIDITY_AMOUNT }); - - // Expect `amount+fee` of assets to be transferred back from the receiver. - uint256 returnAmount = LIQUIDITY_AMOUNT + fee; - expectCallToTransferFrom({ from: address(goodFlashLoanReceiver), to: address(flashLoan), amount: returnAmount }); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(flashLoan) }); - bytes memory data = bytes("Hello World"); - emit FlashLoan({ - initiator: users.admin, - receiver: goodFlashLoanReceiver, - asset: dai, - amount: LIQUIDITY_AMOUNT, - feeAmount: fee, - data: data - }); - - // Execute the flash loan. - bool response = flashLoan.flashLoan({ - receiver: goodFlashLoanReceiver, - asset: address(dai), - amount: LIQUIDITY_AMOUNT, - data: data - }); - - // Assert that the returned response is `true`. - assertTrue(response, "flashLoan response"); - - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = flashLoan.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + uint128(fee); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - } -} diff --git a/test/integration/concrete/flash-loan/flash-loan/flashLoan.tree b/test/integration/concrete/flash-loan/flash-loan/flashLoan.tree deleted file mode 100644 index f2af3ec8b..000000000 --- a/test/integration/concrete/flash-loan/flash-loan/flashLoan.tree +++ /dev/null @@ -1,26 +0,0 @@ -flashLoan.t.sol -├── when delegate called -│ └── it should revert -└── when not delegate called - ├── when the flash loan amount is too high - │ └── it should revert - └── when the flash loan amount is not too high - ├── given the asset is not flash loanable - │ └── it should revert - └── given the asset is flash loanable - ├── when the calculated fee is too high - │ └── it should revert - └── when the calculated fee is not too high - ├── when the flash loan amount is greater than the available liquidity - │ └── it should revert - └── when the flash loan amount is less than or equal to the available liquidity - ├── when the receiver does not return the correct response - │ └── it should revert - └── when the receiver returns the correct response - ├── when there is reentrancy - │ └── it should revert - └── when there is no reentrancy - ├── it should execute the flash loan - ├── it should make the ERC-20 transfers - ├── it should update the protocol revenues - └── it should emit a {FlashLoan} event diff --git a/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.t.sol b/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.t.sol deleted file mode 100644 index 2f52a376c..000000000 --- a/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.t.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { FlashLoan_Integration_Shared_Test } from "../../../shared/flash-loan/FlashLoan.t.sol"; - -contract MaxFlashLoan_Integration_Concrete_Test is FlashLoan_Integration_Shared_Test { - function test_MaxFlashLoan_AssetNotFlashLoanable() external { - uint256 actualAmount = flashLoan.maxFlashLoan(address(dai)); - uint256 expectedAmount = 0; - assertEq(actualAmount, expectedAmount, "maxFlashLoan amount"); - } - - modifier givenAssetFlashLoanable() { - comptroller.toggleFlashAsset(dai); - _; - } - - function test_MaxFlashLoan() external givenAssetFlashLoanable { - uint256 dealAmount = 14_607_904e18; - deal({ token: address(dai), to: address(flashLoan), give: dealAmount }); - uint256 actualAmount = flashLoan.maxFlashLoan(address(dai)); - uint256 expectedAmount = dealAmount; - assertEq(actualAmount, expectedAmount, "maxFlashLoan amount"); - } -} diff --git a/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.tree b/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.tree deleted file mode 100644 index 7eedfcdd9..000000000 --- a/test/integration/concrete/flash-loan/max-flash-loan/maxFlashLoan.tree +++ /dev/null @@ -1,5 +0,0 @@ -maxFlashLoan.t.sol -├── given the asset is not flash loanable -│ └── it should revert -└── given the asset is flash loanable - └── it should return the correct max flash loan diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index 4e956be9c..c2cd2f1cc 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -7,7 +7,7 @@ contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integrat function test_GenerateAccentColor() external { // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); - string memory expectedColor = "hsl(302,69%,44%)"; + string memory expectedColor = "hsl(268,54%,64%)"; assertEq(actualColor, expectedColor, "accentColor"); } } diff --git a/test/integration/fuzz/comptroller/setFlashFee.t.sol b/test/integration/fuzz/comptroller/setFlashFee.t.sol deleted file mode 100644 index e8b27e0f0..000000000 --- a/test/integration/fuzz/comptroller/setFlashFee.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -contract SetFlashFee_Integration_Fuzz_Test is Integration_Test { - modifier givenCallerAdmin() { - _; - } - - function testFuzz_SetFlashFee(UD60x18 newFlashFee) external givenCallerAdmin { - newFlashFee = _bound(newFlashFee, 0, MAX_FEE); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetFlashFee({ admin: users.admin, oldFlashFee: ZERO, newFlashFee: newFlashFee }); - - // Set the new flash fee. - comptroller.setFlashFee(newFlashFee); - - // Assert that the flash fee has been updated. - UD60x18 actualFlashFee = comptroller.flashFee(); - UD60x18 expectedFlashFee = newFlashFee; - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } -} diff --git a/test/integration/fuzz/flash-loan/flashFee.t.sol b/test/integration/fuzz/flash-loan/flashFee.t.sol deleted file mode 100644 index fb73de14a..000000000 --- a/test/integration/fuzz/flash-loan/flashFee.t.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; - -import { FlashLoan_Integration_Shared_Test } from "../../shared/flash-loan/FlashLoan.t.sol"; - -contract FlashFee_Integration_Fuzz_Test is FlashLoan_Integration_Shared_Test { - modifier givenAssetFlashLoanable() { - comptroller.toggleFlashAsset(dai); - _; - } - - /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: - /// - /// - Multiple values for the comptroller flash fee, including zero - /// - Multiple values for the flash loan amount, including zero - function testFuzz_FlashFee(UD60x18 comptrollerFlashFee, uint256 amount) external givenAssetFlashLoanable { - comptrollerFlashFee = _bound(comptrollerFlashFee, 0, MAX_FEE); - comptroller.setFlashFee(comptrollerFlashFee); - uint256 actualFlashFee = flashLoan.flashFee({ asset: address(dai), amount: amount }); - uint256 expectedFlashFee = ud(amount).mul(comptrollerFlashFee).intoUint256(); - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } -} diff --git a/test/integration/fuzz/flash-loan/flashLoan.t.sol b/test/integration/fuzz/flash-loan/flashLoan.t.sol deleted file mode 100644 index c783a2d90..000000000 --- a/test/integration/fuzz/flash-loan/flashLoan.t.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; - -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; - -import { IERC3156FlashBorrower } from "src/interfaces/erc3156/IERC3156FlashBorrower.sol"; -import { Errors } from "src/libraries/Errors.sol"; - -import { FlashLoanFunction_Integration_Shared_Test } from "../../shared/flash-loan/flashLoanFunction.t.sol"; - -contract FlashLoanFunction_Integration_Fuzz_Test is FlashLoanFunction_Integration_Shared_Test { - function setUp() public virtual override { - FlashLoanFunction_Integration_Shared_Test.setUp(); - } - - function testFuzz_RevertWhen_AmountTooHigh(uint256 amount) external whenNotDelegateCalled { - amount = _bound(amount, uint256(MAX_UINT128) + 1, MAX_UINT256); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_AmountTooHigh.selector, amount)); - flashLoan.flashLoan({ - receiver: IERC3156FlashBorrower(address(0)), - asset: address(dai), - amount: amount, - data: bytes("") - }); - } - - function testFuzz_RevertWhen_CalculatedFeeTooHigh(UD60x18 flashFee) - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - { - // Bound the flash fee so that the calculated fee ends up being greater than 2^128. - flashFee = _bound(flashFee, ud(1.1e18), ud(10e18)); - comptroller.setFlashFee(flashFee); - - // Run the test. - uint256 fee = flashLoan.flashFee({ asset: address(dai), amount: MAX_UINT128 }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2FlashLoan_CalculatedFeeTooHigh.selector, fee)); - flashLoan.flashLoan({ - receiver: IERC3156FlashBorrower(address(0)), - asset: address(dai), - amount: MAX_UINT128, - data: bytes("") - }); - } - - /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: - /// - /// - Multiple values for the comptroller flash fee, including zero - /// - Multiple values for the flash loan amount, including zero - /// - Multiple values for the data bytes array, including zero length - function testFuzz_FlashLoanFunction( - UD60x18 comptrollerFlashFee, - uint128 amount, - bytes calldata data - ) - external - whenNotDelegateCalled - whenAmountNotTooHigh - givenAssetFlashLoanable - whenCalculatedFeeNotTooHigh - whenBorrowDoesNotFail - whenNoReentrancy - { - comptrollerFlashFee = _bound(comptrollerFlashFee, 0, MAX_FEE); - comptroller.setFlashFee(comptrollerFlashFee); - - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = flashLoan.protocolRevenues(dai); - - // Load the flash fee. - uint256 fee = flashLoan.flashFee({ asset: address(dai), amount: amount }); - - // Mint the flash loan amount to the contract. - deal({ token: address(dai), to: address(flashLoan), give: amount }); - - // Mint the flash fee to the receiver so that they can repay the flash loan. - deal({ token: address(dai), to: address(goodFlashLoanReceiver), give: fee }); - - // Expect `amount` of assets to be transferred from {SablierV2FlashLoan} to the receiver. - expectCallToTransfer({ to: address(goodFlashLoanReceiver), amount: amount }); - - // Expect `amount+fee` of assets to be transferred back from the receiver. - uint256 returnAmount = amount + fee; - expectCallToTransferFrom({ from: address(goodFlashLoanReceiver), to: address(flashLoan), amount: returnAmount }); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(flashLoan) }); - emit FlashLoan({ - initiator: users.admin, - receiver: goodFlashLoanReceiver, - asset: dai, - amount: amount, - feeAmount: fee, - data: data - }); - - // Execute the flash loan. - bool response = - flashLoan.flashLoan({ receiver: goodFlashLoanReceiver, asset: address(dai), amount: amount, data: data }); - - // Assert that the returned response is `true`. - assertTrue(response, "flashLoan response"); - - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = flashLoan.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + uint128(fee); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - } -} diff --git a/test/integration/fuzz/flash-loan/maxFlashLoan.t.sol b/test/integration/fuzz/flash-loan/maxFlashLoan.t.sol deleted file mode 100644 index 5afbd58d5..000000000 --- a/test/integration/fuzz/flash-loan/maxFlashLoan.t.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { FlashLoan_Integration_Shared_Test } from "../../shared/flash-loan/FlashLoan.t.sol"; - -contract MaxFlashLoan_Integration_Fuzz_Test is FlashLoan_Integration_Shared_Test { - modifier givenAssetFlashLoanable() { - comptroller.toggleFlashAsset(dai); - _; - } - - function testFuzz_MaxFlashLoan(uint256 dealAmount) external givenAssetFlashLoanable { - deal({ token: address(dai), to: address(flashLoan), give: dealAmount }); - uint256 actualAmount = flashLoan.maxFlashLoan(address(dai)); - uint256 expectedAmount = dealAmount; - assertEq(actualAmount, expectedAmount, "maxFlashLoan amount"); - } -} diff --git a/test/integration/shared/flash-loan/FlashLoan.t.sol b/test/integration/shared/flash-loan/FlashLoan.t.sol deleted file mode 100644 index e0609c920..000000000 --- a/test/integration/shared/flash-loan/FlashLoan.t.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { SablierV2FlashLoan } from "src/abstracts/SablierV2FlashLoan.sol"; - -import { FlashLoanMock } from "../../../mocks/flash-loan/FlashLoanMock.sol"; -import { Integration_Test } from "../../Integration.t.sol"; - -/// @notice Common testing logic needed by all {SablierV2FlashLoan} integration tests. -abstract contract FlashLoan_Integration_Shared_Test is Integration_Test { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - SablierV2FlashLoan internal flashLoan; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Integration_Test.setUp(); - - // Deploy the flash loan mock. - flashLoan = new FlashLoanMock(users.admin, comptroller); - - // Set the default flash fee in the comptroller. - comptroller.setFlashFee({ newFlashFee: defaults.FLASH_FEE() }); - } -} diff --git a/test/integration/shared/flash-loan/flashLoanFunction.t.sol b/test/integration/shared/flash-loan/flashLoanFunction.t.sol deleted file mode 100644 index 032b72d97..000000000 --- a/test/integration/shared/flash-loan/flashLoanFunction.t.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; - -import { FlashLoan_Integration_Shared_Test } from "./FlashLoan.t.sol"; - -contract FlashLoanFunction_Integration_Shared_Test is FlashLoan_Integration_Shared_Test { - uint128 internal constant LIQUIDITY_AMOUNT = 8_755_001e18; - - function setUp() public virtual override { - FlashLoan_Integration_Shared_Test.setUp(); - } - - modifier whenNotDelegateCalled() { - _; - } - - modifier whenAmountNotTooHigh() { - _; - } - - modifier givenAssetFlashLoanable() { - if (!comptroller.isFlashAsset(dai)) { - comptroller.toggleFlashAsset(dai); - } - _; - } - - modifier whenCalculatedFeeNotTooHigh() { - _; - } - - modifier whenBorrowDoesNotFail() { - _; - } - - modifier whenNoReentrancy() { - _; - } -} diff --git a/test/invariant/handlers/ComptrollerHandler.sol b/test/invariant/handlers/ComptrollerHandler.sol index c5d9f5e6c..8c374a788 100644 --- a/test/invariant/handlers/ComptrollerHandler.sol +++ b/test/invariant/handlers/ComptrollerHandler.sol @@ -36,18 +36,6 @@ contract ComptrollerHandler is BaseHandler { SABLIER-V2-COMPTROLLER //////////////////////////////////////////////////////////////////////////*/ - function setFlashFee( - uint256 timeJumpSeed, - UD60x18 newFlashFee - ) - external - instrument("setFlashFee") - adjustTimestamp(timeJumpSeed) - { - newFlashFee = _bound(newFlashFee, 0, UNIT); - comptroller.setFlashFee(newFlashFee); - } - function setProtocolFee( uint256 timeJumpSeed, UD60x18 newProtocolFee @@ -59,12 +47,4 @@ contract ComptrollerHandler is BaseHandler { newProtocolFee = _bound(newProtocolFee, 0, MAX_FEE); comptroller.setProtocolFee(asset, newProtocolFee); } - - function toggleFlashAsset(uint256 timeJumpSeed) - external - instrument("toggleFlashAsset") - adjustTimestamp(timeJumpSeed) - { - comptroller.toggleFlashAsset(asset); - } } diff --git a/test/invariant/handlers/FlashLoanHandler.sol b/test/invariant/handlers/FlashLoanHandler.sol deleted file mode 100644 index 8165e152f..000000000 --- a/test/invariant/handlers/FlashLoanHandler.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; - -import { SablierV2FlashLoan } from "src/abstracts/SablierV2FlashLoan.sol"; -import { IERC3156FlashBorrower } from "src/interfaces/erc3156/IERC3156FlashBorrower.sol"; -import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; - -import { TimestampStore } from "../stores/TimestampStore.sol"; -import { BaseHandler } from "./BaseHandler.sol"; - -/// @dev This contract and not {SablierV2FlashLoan} is exposed to Foundry for invariant testing. The point is -/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. -contract FlashLoanHandler is BaseHandler { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierV2Comptroller public comptroller; - SablierV2FlashLoan public flashLoanContract; - IERC3156FlashBorrower internal receiver; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor( - IERC20 asset_, - TimestampStore timestampStore_, - ISablierV2Comptroller comptroller_, - SablierV2FlashLoan flashLoanContract_, - IERC3156FlashBorrower receiver_ - ) - BaseHandler(asset_, timestampStore_) - { - comptroller = comptroller_; - flashLoanContract = flashLoanContract_; - receiver = receiver_; - } - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-FLASH-LOAN - //////////////////////////////////////////////////////////////////////////*/ - - function flashLoan( - uint256 timeJumpSeed, - uint128 amount - ) - external - instrument("flashLoan") - adjustTimestamp(timeJumpSeed) - { - // Only up to `MAX_UINT128` assets can be flash loaned. - uint256 balance = asset.balanceOf(address(this)); - uint128 upperBound = uint128(Math.min(balance, MAX_UINT128)); - amount = boundUint128(amount, 0, upperBound); - - // Only supported assets can be flash loaned. - bool isFlashAsset = comptroller.isFlashAsset(asset); - if (!isFlashAsset) { - return; - } - - // The flash fee must be less than or equal to `MAX_UINT128`. - uint256 fee = flashLoanContract.flashFee(address(asset), amount); - if (fee > type(uint128).max) { - return; - } - - // Mint the flash fee to the receiver so that they can repay the flash loan. - deal({ token: address(asset), to: address(receiver), give: fee }); - - // Some contracts do not inherit from {SablierV2FlashLoan}. - (bool success,) = address(flashLoanContract).staticcall( - abi.encodeWithSelector( - SablierV2FlashLoan.flashLoan.selector, receiver, address(asset), amount, bytes("Some Data") - ) - ); - if (!success) { - return; - } - - // Execute the flash loan. - flashLoanContract.flashLoan({ - receiver: receiver, - asset: address(asset), - amount: amount, - data: bytes("Some Data") - }); - } -} diff --git a/test/mocks/flash-loan/FaultyFlashLoanReceiver.sol b/test/mocks/flash-loan/FaultyFlashLoanReceiver.sol deleted file mode 100644 index 98c18a999..000000000 --- a/test/mocks/flash-loan/FaultyFlashLoanReceiver.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { IERC3156FlashBorrower } from "../../../src/interfaces/erc3156/IERC3156FlashBorrower.sol"; - -contract FaultyFlashLoanReceiver is IERC3156FlashBorrower { - bytes32 internal constant FAULTY_RESPONSE = keccak256("This is a faulty response"); - - function onFlashLoan( - address initiator, - address asset, - uint256 amount, - uint256 fee, - bytes calldata data - ) - external - returns (bytes32 response) - { - initiator; - data; - IERC20(asset).approve({ spender: msg.sender, amount: amount + fee }); - response = FAULTY_RESPONSE; - } -} diff --git a/test/mocks/flash-loan/FlashLoanMock.sol b/test/mocks/flash-loan/FlashLoanMock.sol deleted file mode 100644 index 232c06cb1..000000000 --- a/test/mocks/flash-loan/FlashLoanMock.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -import { SablierV2Base } from "../../../src/abstracts/SablierV2Base.sol"; -import { ISablierV2Comptroller } from "../../../src/interfaces/ISablierV2Comptroller.sol"; -import { SablierV2FlashLoan } from "../../../src/abstracts/SablierV2FlashLoan.sol"; - -/// @dev Needed to test the {SablierV2FlashLoan} abstract. -contract FlashLoanMock is SablierV2FlashLoan { - constructor( - address initialAdmin, - ISablierV2Comptroller initialComptroller - ) - SablierV2Base(initialAdmin, initialComptroller) - { } -} diff --git a/test/mocks/flash-loan/GoodFlashLoanReceiver.sol b/test/mocks/flash-loan/GoodFlashLoanReceiver.sol deleted file mode 100644 index 85c9794dc..000000000 --- a/test/mocks/flash-loan/GoodFlashLoanReceiver.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { IERC3156FlashBorrower } from "../../../src/interfaces/erc3156/IERC3156FlashBorrower.sol"; - -import { Constants } from "../../utils/Constants.sol"; - -contract GoodFlashLoanReceiver is Constants, IERC3156FlashBorrower { - function onFlashLoan( - address initiator, - address asset, - uint256 amount, - uint256 fee, - bytes calldata data - ) - external - returns (bytes32 response) - { - initiator; - data; - IERC20(asset).approve({ spender: msg.sender, amount: amount + fee }); - response = FLASH_LOAN_CALLBACK_SUCCESS; - } -} diff --git a/test/mocks/flash-loan/ReentrantFlashLoanReceiver.sol b/test/mocks/flash-loan/ReentrantFlashLoanReceiver.sol deleted file mode 100644 index e0fbc12a8..000000000 --- a/test/mocks/flash-loan/ReentrantFlashLoanReceiver.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { IERC3156FlashBorrower } from "../../../src/interfaces/erc3156/IERC3156FlashBorrower.sol"; -import { IERC3156FlashLender } from "../../../src/interfaces/erc3156/IERC3156FlashLender.sol"; - -import { Constants } from "../../utils/Constants.sol"; - -contract ReentrantFlashLoanReceiver is Constants, IERC3156FlashBorrower { - function onFlashLoan( - address initiator, - address asset, - uint256 amount, - uint256 fee, - bytes calldata data - ) - external - returns (bytes32 response) - { - initiator; - IERC20(asset).approve({ spender: msg.sender, amount: amount + fee }); - IERC3156FlashLender(msg.sender).flashLoan({ receiver: this, asset: asset, amount: amount, data: data }); - response = FLASH_LOAN_CALLBACK_SUCCESS; - } -} diff --git a/test/unit/concrete/comptroller/flash-fee/flashFee.t.sol b/test/unit/concrete/comptroller/flash-fee/flashFee.t.sol deleted file mode 100644 index 9fe6fb139..000000000 --- a/test/unit/concrete/comptroller/flash-fee/flashFee.t.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Comptroller_Unit_Concrete_Test } from "../Comptroller.t.sol"; - -contract FlashFee_Unit_Concrete_Test is Comptroller_Unit_Concrete_Test { - function setUp() public virtual override { - Comptroller_Unit_Concrete_Test.setUp(); - // Make the Admin the default caller in this test suite. - vm.startPrank({ msgSender: users.admin }); - } - - function test_FlashFee_Zero() external { - UD60x18 actualFlashFee = comptroller.flashFee(); - UD60x18 expectedFlashFee = ZERO; - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } - - function test_FlashFee() external { - comptroller.setFlashFee(defaults.FLASH_FEE()); - UD60x18 actualFlashFee = comptroller.flashFee(); - UD60x18 expectedFlashFee = defaults.FLASH_FEE(); - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } -} diff --git a/test/unit/concrete/comptroller/flash-fee/flashFee.tree b/test/unit/concrete/comptroller/flash-fee/flashFee.tree deleted file mode 100644 index 04e7932b7..000000000 --- a/test/unit/concrete/comptroller/flash-fee/flashFee.tree +++ /dev/null @@ -1,5 +0,0 @@ -flashFee.t.sol -├── given the flash fee has not been set -│ └── it should return zero -└── given the flash fee has been set - └── it should return the correct flash fee diff --git a/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.t.sol b/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.t.sol deleted file mode 100644 index 2efb39738..000000000 --- a/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.t.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Errors } from "src/libraries/Errors.sol"; - -import { Comptroller_Unit_Concrete_Test } from "../Comptroller.t.sol"; - -contract SetFlashFee_Unit_Concrete_Test is Comptroller_Unit_Concrete_Test { - function setUp() public virtual override { - Comptroller_Unit_Concrete_Test.setUp(); - // Make the Admin the default caller in this test suite. - vm.startPrank({ msgSender: users.admin }); - } - - function test_RevertWhen_CallerNotAdmin() external { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - comptroller.setFlashFee({ newFlashFee: MAX_FEE }); - } - - /// @dev The admin is the default caller in the comptroller tests. - modifier whenCallerAdmin() { - _; - } - - function test_SetFlashFee_SameFee() external whenCallerAdmin { - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetFlashFee({ admin: users.admin, oldFlashFee: ZERO, newFlashFee: ZERO }); - comptroller.setFlashFee({ newFlashFee: ZERO }); - - // She the same flash fee. - comptroller.setFlashFee({ newFlashFee: ZERO }); - - // Assert that the flash fee has not changed. - UD60x18 actualFlashFee = comptroller.flashFee(); - UD60x18 expectedFlashFee = ZERO; - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } - - modifier whenNewFee() { - _; - } - - function test_SetFlashFee() external whenCallerAdmin whenNewFee { - UD60x18 newFlashFee = defaults.FLASH_FEE(); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetFlashFee({ admin: users.admin, oldFlashFee: ZERO, newFlashFee: newFlashFee }); - - // She the new flash fee. - comptroller.setFlashFee(newFlashFee); - - // Assert that the flash fee has been updated. - UD60x18 actualFlashFee = comptroller.flashFee(); - UD60x18 expectedFlashFee = newFlashFee; - assertEq(actualFlashFee, expectedFlashFee, "flashFee"); - } -} diff --git a/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.tree b/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.tree deleted file mode 100644 index 9f97bbefd..000000000 --- a/test/unit/concrete/comptroller/set-flash-fee/setFlashFee.tree +++ /dev/null @@ -1,10 +0,0 @@ -setFlashFee.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the new flash fee is the same as the current flash fee - │ ├── it should re-set the flash fee - │ └── it should emit a {SetFlashFee} event - └── when the new flash fee is not the same as the current flash fee - ├── it should set the new flash fee - └── it should emit a {SetFlashFee} event diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 996dad865..4827bc5b3 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.19; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; abstract contract Constants { - bytes32 internal constant FLASH_LOAN_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan"); uint40 internal constant MAY_1_2023 = 1_682_899_200; UD60x18 internal constant MAX_FEE = UD60x18.wrap(0.1e18); // 10% uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 3c5d16699..85e20bec7 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -23,7 +23,6 @@ contract Defaults is Constants { uint40 public constant CLIFF_DURATION = 2500 seconds; uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - UD60x18 public constant FLASH_FEE = UD60x18.wrap(0.0005e18); // 0.05% uint256 public constant MAX_SEGMENT_COUNT = 300; uint40 public immutable MAX_SEGMENT_DURATION; UD60x18 public constant PROTOCOL_FEE = UD60x18.wrap(0.001e18); // 0.1% diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 13192c7a9..da24266d4 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.19; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { IERC3156FlashBorrower } from "../../src/interfaces/erc3156/IERC3156FlashBorrower.sol"; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { Lockup, LockupDynamic, LockupLinear } from "../../src/types/DataTypes.sol"; @@ -45,25 +44,8 @@ abstract contract Events { SABLIER-V2-COMPTROLLER //////////////////////////////////////////////////////////////////////////*/ - event SetFlashFee(address indexed admin, UD60x18 oldFlashFee, UD60x18 newFlashFee); - event SetProtocolFee(address indexed admin, IERC20 indexed asset, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); - event ToggleFlashAsset(address indexed admin, IERC20 indexed asset, bool newFlag); - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-FLASH-LOAN - //////////////////////////////////////////////////////////////////////////*/ - - event FlashLoan( - address indexed initiator, - IERC3156FlashBorrower indexed receiver, - IERC20 indexed asset, - uint256 amount, - uint256 feeAmount, - bytes data - ); - /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index a107d8013..213dddbe1 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -25,7 +25,7 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_COMPTROLLER = - hex"60803461009857601f6104b338819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36103ff90816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060408181526004918236101561001657600080fd5b600092833560e01c9182634d81e51d1461039d5750816375829def146102e5578163907a267b14610253578163b5b3ca2c146101ab578163cb01e30e146100f957508063dcf844a7146100c3578063e07df5b4146100a55763f851a4401461007d57600080fd5b346100a157816003193601126100a1576001600160a01b0360209254169051908152f35b5080fd5b50346100a157816003193601126100a1576020906001549051908152f35b50346100a15760203660031901126100a157806020926001600160a01b036100e96103d7565b1681526003845220549051908152f35b9050346101a75760203660031901126101a7576101146103d7565b6001600160a01b03918285541633810361017a575050169081835260026020528083209081549160ff8316159260ff84169060ff1916179055519081527f8cd3a7bc46b26a3b0c07a05a47af78abcaa647626f631d92ea64f8867b23bbec60203392a380f35b84516331b339a960e21b81526001600160a01b039091169181019182523360208301529081906040010390fd5b8280fd5b9050346101a757816003193601126101a7576101c56103d7565b90602435916001600160a01b039182865416338103610226575050907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526003602052808520928084549455815193845260208401523392a380f35b85516331b339a960e21b81526001600160a01b039091169181019182523360208301529081906040010390fd5b919050346101a75760203660031901126101a7578135916001600160a01b038454163381036102b85750507fc059ba3e07a1c4d1fa8845bdb2af2dd85e844684e0a59e6073499e4338788465906001549280600155815193845260208401523392a280f35b82516331b339a960e21b81526001600160a01b039091169181019182523360208301529081906040010390fd5b919050346101a75760203660031901126101a7578135916001600160a01b03918284168094036103995784549283169033820361036d575050507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b516331b339a960e21b81526001600160a01b039091169181019182523360208301529081906040010390fd5b8480fd5b849084346101a75760203660031901126101a75760ff906020936001600160a01b036103c76103d7565b1681526002855220541615158152f35b600435906001600160a01b03821682036103ed57565b600080fdfea164736f6c6343000817000a"; + hex"60803461009857601f6102d538819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361022190816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816375829def1461014c57508063b5b3ca2c146100ac578063dcf844a7146100765763f851a4401461004e57600080fd5b346100725781600319360112610072576001600160a01b0360209254169051908152f35b5080fd5b503461007257602036600319011261007257806020926001600160a01b0361009c6101f9565b1681526001845220549051908152f35b50346100725780600319360112610072576100c56101f9565b602435906001600160a01b0390818554163381036101245750907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526001602052808520928084549455815193845260208401523392a380f35b84516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b83903461007257602036600319011261007257600435906001600160a01b03908183168093036101f55783549182163381036101d25750507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6331b339a960e21b82526001600160a01b03166004820152336024820152604490fd5b8380fd5b600435906001600160a01b038216820361020f57565b600080fdfea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = hex"60c0346200046e57601f62005be438819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a05260016009556040516157509081620004948239608051816132f7015260a051818181610f7a01526134180152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126f55750806306fdde0314612630578063081812fc14612612578063095ea7b31461247e5780631400ecec146123d957806316844456146121155780631c1cdd4c146120af5780631e99d5691461209157806323b872dd1461206857806339a73c031461202557806340e58ee514611dd1578063425d30dd14611db357806342842e0e14611d6357806342966c6814611bd35780634857501f14611b5d5780634869e12d14611b215780635fe3b56714611afa5780636352211e14611acb5780636d0cee7514611a7357806370a08231146119c957806375829def146119375780637cad6cd1146118655780637de6b1db146116555780638659c2701461135c578063894e9a0d146110ef5780638bad38dd146110735780638f69b99314610ff05780639067b67714610f9d5780639188ec8414610f6257806395d89b4114610e52578063a22cb46514610d81578063a2ffb89714610c9f578063a6202bf214610b96578063a80fc07114610b41578063ad35efd414610ade578063b256456914610ac0578063b637b86514610a60578063b88d4fde146109d7578063b8a3be66146109a0578063b971302a1461094e578063bc063e1a1461092b578063bc2be1be146108d8578063c156a11d14610820578063c33cd35e146106c1578063c87b56dd1461058e578063cc364f48146104f4578063d4dbd20b1461049f578063d511609f14610450578063d975dfed14610403578063e985e9c5146103ac578063ea5ead191461037e578063eac8f5b814610312578063f590c176146102ea578063f851a440146102c35763fdd46d601461027c57600080fd5b346102be5760603660031901126102be57610295612822565b6044356001600160801b03811681036102be576102bc916102b46132ed565b6004356131da565b005b600080fd5b346102be5760003660031901126102be5760206001600160a01b0360005416604051908152f35b346102be5760203660031901126102be576020610308600435612e21565b6040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102be5760403660031901126102be576102bc60043561039d612822565b6103a6826140c2565b91612e52565b346102be5760403660031901126102be576103c561280c565b6103cd612822565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916140c2565b6001600160801b0360405191168152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602060026040600020015460801c604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102be5760203660031901126102be57600435600060206040516105188161295c565b828152015280600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526040806000205464ffffffffff82519161055b8361295c565b818160a01c16835260c81c16602082015261058c825180926020908164ffffffffff91828151168552015116910152565bf35b346102be576020806003193601126102be57600435906105cc6105c78360005260056020526001600160a01b0360406000205416151590565b612bdb565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106b55760009261063c575b506106386040519282849384528301906127e7565b0390f35b9091503d806000833e61064f81836129a9565b81019082818303126102be5780519067ffffffffffffffff82116102be570181601f820112156102be578051610684816129cb565b9261069260405194856129a9565b8184528482840101116102be576106ae918480850191016127c4565b9082610623565b6040513d6000823e3d90fd5b346102be57600319602036820181136102be5760043567ffffffffffffffff928382116102be576101409082360301126102be576106fd6132ed565b6040519261070a8461293f565b61071682600401612838565b845261072460248301612a69565b602085015261073560448301612916565b604085015261074660648301612916565b91606092606086015261075b60848201612838565b608086015261076c60a482016129e7565b60a086015261077d60c48201612838565b60c086015261078f3660e48301612b04565b60e08601526101248101359182116102be5701366023820112156102be576004810135926107bc84612a51565b936107ca60405195866129a9565b80855260246060602087019202840101923684116102be57602401905b838210610808576020610800888861010082015261336a565b604051908152f35b8285916108153685612a7b565b8152019101906107e7565b346102be5760403660031901126102be5760043561083c612822565b906108456132ed565b80600052600b60205260ff60016040600020015460a81c1615610367578060005260056020526001600160a01b0360406000205416918233036108b5576102bc9261088f836140c2565b6001600160801b0381166108a4575b50613ddb565b6108af908285612e52565b8461089e565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102be5760003660031901126102be57602060405167016345785d8a00008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be57600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102be5760803660031901126102be576109f061280c565b6109f8612822565b6064359167ffffffffffffffff83116102be57366023840112156102be57826004013591610a25836129cb565b92610a3360405194856129a9565b80845236602482870101116102be5760208160009260246102bc9801838801378501015260443591612d8b565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052610638610aac6004604060002001612cc4565b6040519182916020835260208301906128b2565b346102be5760203660031901126102be576020610308600435612d54565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757610b1890613c75565b6040516005821015610b2b576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102be5760203660031901126102be57610baf61280c565b6001600160a01b038060005416338103610c7657508116908160005260026020526001600160801b0360406000205416908115610c455781610c179184600052600260205260406000206fffffffffffffffffffffffffffffffff198154169055339061405a565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102be5760603660031901126102be5767ffffffffffffffff6004358181116102be57610cd1903690600401612881565b9190610cdb612822565b916044359081116102be57610cf4903690600401612881565b92610cfd6132ed565b838503610d4a5760005b858110610d1057005b80610d44610d216001938988612c4b565b3584610d36610d31858b8a612c4b565b612af0565b91610d3f6132ed565b6131da565b01610d07565b60448585604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102be5760403660031901126102be57610d9a61280c565b602435908115158092036102be576001600160a01b031690813314610e0e57336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102be5760003660031901126102be5760405160006004549060018260011c9160018416918215610f58575b6020948585108414610f42578587948686529182600014610f22575050600114610ec5575b50610eb1925003836129a9565b6106386040519282849384528301906127e7565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610f0a575050610eb1935082010185610ea4565b80548389018501528794508693909201918101610ef3565b60ff191685820152610eb195151560051b8501019250879150610ea49050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610e7f565b346102be5760003660031901126102be5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761102a90613c75565b600581101580610b2b5760028214908115611066575b8115611054575b6020826040519015158152f35b9050610b2b5760046020911482611047565b5050600381146000611040565b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c76575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102be5760203660031901126102be5760606101406040516111118161298c565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152611155612c71565b6101208201520152600435600052600b60205260ff60016040600020015460a81c161561134457600435600052600b602052604060002061123860046040519261119e8461298c565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015261122c60028201612c90565b61012085015201612cc4565b610140820152611249600435613c75565b906005821015610b2b5760026101409214611338575b610638604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261132461012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c08301906128b2565b6000606082015261125f565b602460405162b8e7e760e51b81526004356004820152fd5b346102be576020806003193601126102be5760043567ffffffffffffffff81116102be5761138e903690600401612881565b906113976132ed565b6000915b8083106113a457005b6113af838284612c4b565b35926113b96132ed565b6113c284612ba4565b156113df5760248460405190634a5541ef60e01b82526004820152fd5b6113eb84929394612e21565b61163d5761140f82600052600b6020526001600160a01b0360406000205416331490565b156108b55761141d82613282565b82600052600b8087526114366002604060002001612c90565b906001600160801b0392838351168482161015611625578560005281895260ff60406000205460f01c161561160d57906114a482858b61149a7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509683895116612a38565b9601511690612a38565b9580600052818a526040600020938a855498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617875560038882169788156115f3575b0197831697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a16958691600584528b604060002054169687945260019b8c6040600020015416946115408b858861405a565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b6115a0575b505050505001919061139b565b813b156102be576000608492819560405197889687956372eba20360e01b875260048701526024860152604485015260648401525af16115e4575b80808080611593565b6115ed90612978565b856115db565b60018101600160a01b60ff60a01b198254161790556114ec565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102be576020806003193601126102be57600435906116736132ed565b81600052600b815260ff60016040600020015460a81c161561184e5761169882613c75565b6005811015610b2b57600481036116c15760248360405190634a5541ef60e01b82526004820152fd5b600381036116e1576024836040519063fe19f19f60e01b82526004820152fd5b6002146118365761170882600052600b6020526001600160a01b0360406000205416331490565b156108b55781600052600b815260ff60406000205460f01c161561181e5781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b6117af575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102be57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f341a0bd90000000000000000000000000000000000000000000000000000000083528760048401525af1156117835761181890612978565b83611783565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c765750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116119215760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102be5760203660031901126102be5761195061280c565b6000546001600160a01b03808216923384036119a2576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102be5760203660031901126102be576001600160a01b036119ea61280c565b168015611a095760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57600435611aaa6105c78260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be576020611ae9600435612c26565b6001600160a01b0360405191168152f35b346102be5760003660031901126102be5760206001600160a01b0360015416604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f602091613fdf565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576000611b9982613c75565b6005811015610b2b57600203611bb7575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611baa565b346102be5760203660031901126102be57600435611bef6132ed565b611bf881612ba4565b15611d3257611c0681613f76565b15611d1257611c1481612c26565b611c1d82612d54565b159081611d09575b81611cf6575b50611cde57602081611c5d7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612c26565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611c2b565b60009150611c25565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102be57611d713661284c565b60405191602083019383851067ffffffffffffffff861117611d9d576102bc9460405260008452612d8b565b634e487b7160e01b600052604160045260246000fd5b346102be5760203660031901126102be576020610308600435612ba4565b346102be576020806003193601126102be5760043590611def6132ed565b611df882612ba4565b15611e155760248260405190634a5541ef60e01b82526004820152fd5b611e1e82612e21565b61163d57611e4282600052600b6020526001600160a01b0360406000205416331490565b156108b557611e5082613282565b9180600052600b8252611e696002604060002001612c90565b906001600160801b03938483511685821610156118365781600052600b845260ff60406000205460f01c161561181e57808585611eac611eb69483885116612a38565b9501511690612a38565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716178755600388861697881561200b575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b87526001604060002001541694611f948d858861405a565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b611fc657005b813b156102be576000608492819560405197889687956372eba20360e01b875260048701526024860152604485015260648401525af161200257005b6102bc90612978565b60018101600160a01b60ff60a01b19825416179055611f1f565b346102be5760203660031901126102be576001600160a01b0361204661280c565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102be576102bc6120793661284c565b9161208c6120878433613cfc565b612b33565b613ddb565b346102be5760003660031901126102be576020600954604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576120e990613c75565b6005811015610b2b57806020911590811561210a575b506040519015158152f35b6001915014826120ff565b346102be57602060031981813601126102be576004359067ffffffffffffffff908183116102be57610120833603918201126102be576121536132ed565b61010483013590602219018112156102be578201916004830135928284116102be57602481016060916060860280360383136102be5760249061219588612a51565b976121a3604051998a6129a9565b8852888801920101913683116102be57905b878383106123c2578787878251906121cc82612a51565b916121da60405193846129a9565b808352601f196121e982612a51565b018660005b8281106123ac5750505064ffffffffff90814216946001600160801b03968761221682613349565b515116828a61222484613349565b510151168580604061223586613349565b510151168a0116906040519261224a84612923565b83528b830152604082015261225e87613349565b5261226886613349565b506001938660015b8a8c87831061232b57908b846001600160a01b038c60a4810135828116908190036102be57610800956122eb9561231b946122ad60248601612acf565b6122b960448701612acf565b6122c560648801612adc565b916122d288600401612adc565b94846122e060848b01612af0565b966040519d8e61293f565b168c528d8c0152151560408b0152151560608a01521660808801521660a086015260c085015260c4369101612b04565b60e083015261010082015261336a565b88938580604061235f8b8661234f8a8e9a612346828d613356565b5151169a613356565b5101511694600019890190613356565b51015116816040612370888c613356565b510151160116916040519361238485612923565b84528301526040820152612398828b613356565b526123a3818a613356565b50018790612270565b6123b4612c71565b8282880101520187906121ee565b84916123ce3685612a7b565b8152019101906121b5565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675760209060009080600052600b8352604060002060ff815460f01c168061246c575b612443575b50506001600160801b0360405191168152f35b61246592506001600160801b03600261245f9201541691613282565b90612a38565b8280612430565b5060ff600182015460a01c161561242b565b346102be5760403660031901126102be5761249761280c565b602435906001600160a01b0380806124ae85612c26565b169216918083146125a857803314908115612583575b5015612519578260005260076020526040600020826001600160a01b03198254161790556124f183612c26565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff60406000205416846124c4565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be576020611ae96004356129fb565b346102be5760003660031901126102be5760405160006003549060018260011c91600184169182156126eb575b6020948585108414610f42578587948686529182600014610f2257505060011461268e5750610eb1925003836129a9565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106126d3575050610eb1935082010185610ea4565b805483890185015287945086939092019181016126bc565b92607f169261265d565b346102be5760203660031901126102be57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102be57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561279a575b8115612770575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612769565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612762565b60005b8381106127d75750506000910152565b81810151838201526020016127c7565b90602091612800815180928185528580860191016127c4565b601f01601f1916010190565b600435906001600160a01b03821682036102be57565b602435906001600160a01b03821682036102be57565b35906001600160a01b03821682036102be57565b60609060031901126102be576001600160a01b039060043582811681036102be579160243590811681036102be579060443590565b9181601f840112156102be5782359167ffffffffffffffff83116102be576020808501948460051b0101116102be57565b90815180825260208080930193019160005b8281106128d2575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128c4565b359081151582036102be57565b6060810190811067ffffffffffffffff821117611d9d57604052565b610120810190811067ffffffffffffffff821117611d9d57604052565b6040810190811067ffffffffffffffff821117611d9d57604052565b67ffffffffffffffff8111611d9d57604052565b610160810190811067ffffffffffffffff821117611d9d57604052565b90601f8019910116810190811067ffffffffffffffff821117611d9d57604052565b67ffffffffffffffff8111611d9d57601f01601f191660200190565b35906001600160801b03821682036102be57565b612a1e6105c78260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161192157565b67ffffffffffffffff8111611d9d5760051b60200190565b359064ffffffffff821682036102be57565b91908260609103126102be57604051612a9381612923565b8092612a9e816129e7565b825260208101359067ffffffffffffffff821682036102be576040612aca918193602086015201612a69565b910152565b3580151581036102be5790565b356001600160a01b03811681036102be5790565b356001600160801b03811681036102be5790565b91908260409103126102be57604051612b1c8161295c565b6020808294612b2a81612838565b84520135910152565b15612b3a57565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460a01c1690565b15612be257565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c48811515612bdb565b90565b9190811015612c5b5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190612c7e82612923565b60006040838281528260208201520152565b90604051612c9d81612923565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612cd081612a51565b92604093612ce160405191826129a9565b82815280946020809201926000526020600020906000935b858510612d0857505050505050565b60018481928451612d1881612923565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cf9565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460b01c1690565b90612daf939291612d9f6120878433613cfc565b612daa838383613ddb565b6146f5565b15612db657565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260406000205460f81c90565b929192612e5d6132ed565b612e6681612ba4565b6131c257612e8a81600052600b6020526001600160a01b0360406000205416331490565b918215806131b2575b6108b557600092828452602093600585526001600160a01b039660409388858420541693806131a6575b6131685788811698891561313f576001600160801b0380841693841561310f57612f00612ee98a613fdf565b8a8852600b8c5260028a8920015460801c90612a38565b82811686116130c75750918491612f5f612f2d612f9895600b8e8e8c525260028c8b20015460801c6140ea565b8b8952600b8d5260028b8a200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c90565b90612f7a818d8401511692828c818351169201511690612a38565b161115613098575b888652600b8a526001888720015416928361405a565b88867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d898851868152a4823314158061308e575b612fff575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b823b1561308a5760847ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7979883865195869485937f13375c3b0000000000000000000000000000000000000000000000000000000085528a6004860152336024860152604485015260648401525af161307b575b859481612fd1565b61308490612978565b38613073565b5080fd5b50823b1515612fcc565b888652600b8a5287862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612f82565b88517fa1fb2bbc000000000000000000000000000000000000000000000000000000008152600481018b90526001600160801b03928316602482015291166044820152606490fd5b6024898951907fd2aabcd90000000000000000000000000000000000000000000000000000000082526004820152fd5b600486517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b85896064928751927f5b97ed720000000000000000000000000000000000000000000000000000000084526004840152336024840152166044820152fd5b50838982161415612ebd565b506131bc82613f76565b15612e93565b60249060405190634a5541ef60e01b82526004820152fd5b9291926131e681612ba4565b6131c25761320a81600052600b6020526001600160a01b0360406000205416331490565b91821580613272575b6108b557600092828452602093600585526001600160a01b03966040938885842054169380613266575b6131685788811698891561313f576001600160801b0380841693841561310f57612f00896140c2565b5083898216141561323d565b5061327c82613f76565b15613213565b64ffffffffff80421682600052600b602052604060002091825482828260a01c1610156132e35760c81c1611156132d15760040154600110156132c857612c48906141d9565b612c4890614105565b6001600160801b039150600201541690565b5050505050600090565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361331f57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c5b5760200190565b8051821015612c5b5760209160051b010190565b906001600160a01b036001541660206001600160a01b0360c0850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106b557600090613c41575b6133eb91506001600160801b0360a08501511690602060e08601510151916143c4565b6001600160801b0381511661010084015164ffffffffff6020860151168215613c175781518015613bed577f00000000000000000000000000000000000000000000000000000000000000008111613bbc575064ffffffffff604061344f84613349565b51015116811015613b655750600090819082815184905b808210613ad2575050505064ffffffffff421664ffffffffff8216811015613a925750506001600160801b0316808203613a5b5750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b0360c083015116600184015490750100000000000000000000000000000000000000000060408501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff000000000000000000000000000000000000000000006060890151151560b01b16921617171760018601556001600160a01b0384511691610100850151926040613581855195600019870190613356565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060208b015160a01b169660c81b169460f01b16911617171717845560005b81811061398b575050600185016009556001600160a01b0360c08301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b0360c0840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036080830151168015613947576136c86136c28760005260056020526001600160a01b0360406000205416151590565b15614503565b6136d186612d54565b158061393e575b80613936575b61391e5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7916137296136c28960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a16137b96001600160a01b0360c0840151166001600160801b0380845116816020860151160116903090339061454e565b6001600160801b03604082015116806138ef575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6138ac6001600160a01b03845116926001600160a01b03608086015116946001600160a01b0360c082015116966138e46138c460408401511515928c606086015115156001600160a01b0360e061010089015194549864ffffffffff6040519a6138588c61295c565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e08801528601906128b2565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613918906001600160a01b0360c0850151166001600160a01b0360e0860151511690339061454e565b386137cd565b60248660405190630da9b01360e01b82526004820152fd5b5060006136de565b508015156136d8565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b61399a81610100860151613356565b519060048601549168010000000000000000831015611d9d5760018301806004890155831015612c5b5760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b16931617171790550161361d565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613af6906001600160801b03613aed8588613356565b515116906140ea565b9364ffffffffff806040613b0a8685613356565b51015116941680851115613b28575060018493019192919092613466565b8385606492604051927f7b0bada8000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613b7684613349565b5101516040517fb4c9e52c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d602011613c6d575b81613c5b602093836129a9565b810103126102be576133eb90516133c8565b3d9150613c4e565b80600052600b602052604060002060ff600182015460a01c16600014613c9c575050600490565b805460f81c613cf5575460a01c64ffffffffff164210613cef57613cbf81613282565b90600052600b6020526001600160801b038060026040600020015416911610600014613cea57600190565b600290565b50600090565b5050600390565b906001600160a01b038080613d1084612c26565b16931691838314938415613d43575b508315613d2d575b50505090565b613d39919293506129fb565b1614388080613d27565b909350600052600860205260406000208260005260205260ff604060002054169238613d1f565b15613d7157565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b90613e049291613dea83612c26565b916001600160a01b03948593848094169687911614613d6a565b1690811580613f0d57613e1684612d54565b159081613f04575b5080613efb575b613ee35791808492613e657ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796602096613e5e85612c26565b1614613d6a565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515613e25565b90501538613e1e565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b60009080825260056020526001600160a01b038060408420541692833314938415613fbb575b50508215613fa957505090565b909150613fb633926129fb565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613f9c565b80600052600b602052613ff86002604060002001612c90565b81600052600b602052604060002060ff600182015460a01c1660001461402b57506001600160801b039150602001511690565b5460f81c61403d5750612c4890613282565b612c4891506001600160801b036040818351169201511690612a38565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611d9d576140c0926040526145b9565b565b612c48906140cf81613fdf565b90600052600b60205260026040600020015460801c90612a38565b9190916001600160801b038080941691160191821161192157565b64ffffffffff61413a600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614888565b91808252600b602052600460408320018054156141c55790829167ffffffffffffffff93526141976020832054828452600b6020526141926001600160801b03968760026040882001541696879360801c1690614978565b6149e6565b9283136141ad5750506141a990614ad0565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b6020526040908181208251936142008561298c565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c16151561010088015261014061429b600461428c60028801612c90565b966101208b0197885201612cc4565b97019187835280876142ad889a613349565b5101511693828288965b161061438c5750916143416141929284888161434698976001600160801b039e8f6142e38b8a51613356565b5151169d8a8f9b602061430067ffffffffffffffff928d51613356565b51015116998483614312848451613356565b51015116965081156143805761433092935051906000190190613356565b5101511680925b0316920316614888565b614978565b92831361435f5750506143598391614ad0565b16011690565b51602001519293928316928416831015915061437b9050575090565b905090565b50505051168092614337565b8094986001600160801b0390816143a48c8851613356565b51511601169801938282808a6143bb898951613356565b510151166142b7565b9092916143cf612c71565b936001600160801b03928381169182156144db5767016345785d8a00008082116144a45780851161446d57506144198561440a8193866155fc565b169460208901958652846155fc565b1691846144306040890194808652828751166140ea565b1610156144575761444984918261445295511690612a38565b91511690612a38565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516144ee81612923565b60008152600060208201526000604082015290565b1561450a57565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611d9d576140c0926040525b6001600160a01b0316906146196040516145d28161295c565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16146136146c5565b916156ab565b80519182159184831561469e575b5050509050156146345750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91938180945001031261308a578201519081151582036146c2575080388084614627565b80fd5b3d156146f0573d906146d6826129cb565b916146e460405193846129a9565b82523d6000602084013e565b606090565b9290803b1561487f5761475f916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906127e7565b03916000968791165af19082908261481e575b50506147f8576147806146c5565b805190816147f35760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614877575b8161483b602093836129a9565b8101031261308a5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036146c25750903880614772565b3d915061482e565b50505050600190565b600160ff1b80821490811561496e575b5061494457600081121561493b576148c1816000035b6000841215614934578360000390614b0c565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148fd57600019911813156148f75790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614b0c565b6148c1816148ae565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614898565b80614993575061498e57670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146149e05750806149b8575050670de0b6b3a764000090565b670de0b6b3a764000081146149dc576149d790614192612c4893614c06565b614d48565b5090565b91505090565b600160ff1b808214908115614ac6575b50614a9c576000811215614a9357614a1f816000035b6000841215614a8c5783600003906155fc565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614a5557600019911813156148f75790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906155fc565b614a1f81614a0c565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386149f6565b60008112614adb5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614bc85782851015614b8c57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614bd6570490565b634e487b7160e01b600052601260045260246000fd5b8015614bd6576ec097ce7bc90715b34b9f10000000000590565b80600080831315614d1757670de0b6b3a764000092838112614cf457506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ce857506706f05b59d3b20000905b848213614cbc5750505050500290565b808391020590671bc16d674ec80000821215614cdb575b831d90614cac565b8091950194831d90614cd3565b93505093925050020290565b6000199392508015614bd6576ec097ce7bc90715b34b9f10000000000591614c27565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614d775768033dd1780914b97114198112613cef57614d6e90600003614d48565b612c4890614bec565b680a688906bd8affffff81136155cb57670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166154ae575b66ff00000000000083166153a6575b65ff000000000083166152a6575b64ff0000000083166151ae575b63ff00000083166150be575b62ff00008316614fd6575b61ff008316614ef6575b60ff8316614e1f575b02911c60bf031c90565b60808316614ee4575b838316614ed2575b60208316614ec0575b60108316614eae575b60088316614e9c575b60048316614e8a575b60028316614e78575b6001831615614e15576801000000000000000102831c614e15565b6801000000000000000102831c614e5d565b6801000000000000000302831c614e54565b6801000000000000000602831c614e4b565b6801000000000000000b02831c614e42565b6801000000000000001602831c614e39565b6801000000000000002c02831c614e30565b6801000000000000005902831c614e28565b6180008316614fc4575b6140008316614fb2575b6120008316614fa0575b6110008316614f8e575b6108008316614f7c575b6104008316614f6a575b6102008316614f58575b610100831615614e0c57680100000000000000b102831c614e0c565b6801000000000000016302831c614f3c565b680100000000000002c602831c614f32565b6801000000000000058c02831c614f28565b68010000000000000b1702831c614f1e565b6801000000000000162e02831c614f14565b68010000000000002c5d02831c614f0a565b680100000000000058b902831c614f00565b6280000083166150ac575b62400000831661509a575b622000008316615088575b621000008316615076575b620800008316615064575b620400008316615052575b620200008316615040575b62010000831615614e02576801000000000000b17202831c614e02565b680100000000000162e402831c615023565b6801000000000002c5c802831c615018565b68010000000000058b9102831c61500d565b680100000000000b172102831c615002565b68010000000000162e4302831c614ff7565b680100000000002c5c8602831c614fec565b6801000000000058b90c02831c614fe1565b6380000000831661519c575b6340000000831661518a575b63200000008316615178575b63100000008316615166575b63080000008316615154575b63040000008316615142575b63020000008316615130575b6301000000831615614df75768010000000000b1721802831c614df7565b6801000000000162e43002831c615112565b68010000000002c5c86002831c615106565b680100000000058b90c002831c6150fa565b6801000000000b17217f02831c6150ee565b680100000000162e42ff02831c6150e2565b6801000000002c5c85fe02831c6150d6565b68010000000058b90bfc02831c6150ca565b6480000000008316615294575b6440000000008316615282575b6420000000008316615270575b641000000000831661525e575b640800000000831661524c575b640400000000831661523a575b6402000000008316615228575b640100000000831615614deb57680100000000b17217f802831c614deb565b68010000000162e42ff102831c615209565b680100000002c5c85fe302831c6151fc565b6801000000058b90bfce02831c6151ef565b68010000000b17217fbb02831c6151e2565b6801000000162e42fff002831c6151d5565b68010000002c5c8601cc02831c6151c8565b680100000058b90c0b4902831c6151bb565b658000000000008316615394575b654000000000008316615382575b652000000000008316615370575b65100000000000831661535e575b65080000000000831661534c575b65040000000000831661533a575b650200000000008316615328575b65010000000000831615614dde576801000000b17218355102831c614dde565b680100000162e430e5a202831c615308565b6801000002c5c863b73f02831c6152fa565b68010000058b90cf1e6e02831c6152ec565b680100000b1721bcfc9a02831c6152de565b68010000162e43f4f83102831c6152d0565b680100002c5c89d5ec6d02831c6152c2565b6801000058b91b5bc9ae02831c6152b4565b6680000000000000831661549c575b6640000000000000831661548a575b66200000000000008316615478575b66100000000000008316615466575b66080000000000008316615454575b66040000000000008316615442575b66020000000000008316615430575b6601000000000000831615614dd05768010000b17255775c0402831c614dd0565b6801000162e525ee054702831c61540f565b68010002c5cc37da949202831c615400565b680100058ba01fb9f96d02831c6153f1565b6801000b175effdc76ba02831c6153e2565b680100162f3904051fa102831c6153d3565b6801002c605e2e8cec5002831c6153c4565b68010058c86da1c09ea202831c6153b5565b67800000000000000083166155ac575b674000000000000000831661559a575b6720000000000000008316615588575b6710000000000000008316615576575b6708000000000000008316615564575b6704000000000000008316615552575b6702000000000000008316615540575b670100000000000000831615614dc157680100b1afa5abcbed6102831c614dc1565b68010163da9fb33356d802831c61551e565b680102c9a3e778060ee702831c61550e565b6801059b0d31585743ae02831c6154fe565b68010b5586cf9890f62a02831c6154ee565b6801172b83c7d517adce02831c6154de565b6801306fe0a31b7152df02831c6154ce565b5077b504f333f9de6484800000000000000000000000000000006154be565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461569a57670de0b6b3a7640000908183101561566357947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9192901561570c57508151156156bf575090565b3b156156c85790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501561571f5750805190602001fd5b6108d49060405191829162461bcd60e51b83526020600484015260248301906127e756fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = From 2d8f1fd1a41913a46d2d8c2976c2b9b055c7da79 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Thu, 11 Jan 2024 15:49:21 +0200 Subject: [PATCH 031/132] Add sender hook and rename recipient's hook functions (#781) * refactor: rename recipient's hook interface refactor: rename recipient's hook functions * feat: add hook for sender refactor: add getSender function in SablierV2Lockup test: update tests accordingly * build: include ISablierV2Sender in prepare-artifacts * test: update Precompiles bytecode * refactor: use sender address to check the caller when calling the hook test: correct function name --- shell/prepare-artifacts.sh | 3 +- src/SablierV2LockupDynamic.sol | 12 +- src/SablierV2LockupLinear.sol | 12 +- src/abstracts/SablierV2Lockup.sol | 25 +- ...pRecipient.sol => ISablierV2Recipient.sol} | 10 +- src/interfaces/hooks/ISablierV2Sender.sol | 19 ++ test/Base.t.sol | 4 + test/integration/Integration.t.sol | 6 + .../concrete/lockup/cancel/cancel.t.sol | 10 +- .../concrete/lockup/renounce/renounce.t.sol | 10 +- .../concrete/lockup/withdraw/withdraw.t.sol | 285 +++++++++++------- .../concrete/lockup/withdraw/withdraw.tree | 102 ++++--- .../nft-descriptor/generateAccentColor.t.sol | 2 +- test/mocks/hooks/GoodRecipient.sol | 10 +- test/mocks/hooks/GoodSender.sol | 13 + test/mocks/hooks/ReentrantRecipient.sol | 10 +- test/mocks/hooks/ReentrantSender.sol | 15 + test/mocks/hooks/RevertingRecipient.sol | 10 +- test/mocks/hooks/RevertingSender.sol | 14 + test/utils/Precompiles.sol | 4 +- 20 files changed, 383 insertions(+), 193 deletions(-) rename src/interfaces/hooks/{ISablierV2LockupRecipient.sol => ISablierV2Recipient.sol} (87%) create mode 100644 src/interfaces/hooks/ISablierV2Sender.sol create mode 100644 test/mocks/hooks/GoodSender.sol create mode 100644 test/mocks/hooks/ReentrantSender.sol create mode 100644 test/mocks/hooks/RevertingSender.sol diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index 22b5892e9..fc328f2fa 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -44,7 +44,8 @@ cp out-optimized/IERC721.sol/IERC721.json $erc721 cp out-optimized/IERC721Metadata.sol/IERC721Metadata.json $erc721 hooks=./artifacts/interfaces/hooks -cp out-optimized/ISablierV2LockupRecipient.sol/ISablierV2LockupRecipient.json $hooks +cp out-optimized/ISablierV2Recipient.sol/ISablierV2Recipient.json $hooks +cp out-optimized/ISablierV2Sender.sol/ISablierV2Sender.json $hooks libraries=./artifacts/libraries cp out-optimized/Errors.sol/Errors.json $libraries diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index e8a15a4cb..c97b00008 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -13,7 +13,7 @@ import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; 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 { ISablierV2Recipient } from "./interfaces/hooks/ISablierV2Recipient.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; import { Errors } from "./libraries/Errors.sol"; import { Helpers } from "./libraries/Helpers.sol"; @@ -142,7 +142,13 @@ contract SablierV2LockupDynamic is } /// @inheritdoc ISablierV2Lockup - function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender) { + function getSender(uint256 streamId) + public + view + override(ISablierV2Lockup, SablierV2Lockup) + notNull(streamId) + returns (address sender) + { sender = _streams[streamId].sender; } @@ -521,7 +527,7 @@ contract SablierV2LockupDynamic is // 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({ + try ISablierV2Recipient(recipient).onLockupStreamCanceled({ streamId: streamId, sender: sender, senderAmount: senderAmount, diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 1f0c4da75..bab2aee55 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -11,7 +11,7 @@ import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; 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 { ISablierV2Recipient } from "./interfaces/hooks/ISablierV2Recipient.sol"; import { Errors } from "./libraries/Errors.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupLinear } from "./types/DataTypes.sol"; @@ -125,7 +125,13 @@ contract SablierV2LockupLinear is } /// @inheritdoc ISablierV2Lockup - function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender) { + function getSender(uint256 streamId) + public + view + override(ISablierV2Lockup, SablierV2Lockup) + notNull(streamId) + returns (address sender) + { sender = _streams[streamId].sender; } @@ -436,7 +442,7 @@ contract SablierV2LockupLinear is // 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({ + try ISablierV2Recipient(recipient).onLockupStreamCanceled({ streamId: streamId, sender: sender, senderAmount: senderAmount, diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index a3a323f3e..29a86b432 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -8,7 +8,8 @@ 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 { ISablierV2Recipient } from "../interfaces/hooks/ISablierV2Recipient.sol"; +import { ISablierV2Sender } from "../interfaces/hooks/ISablierV2Sender.sol"; import { Errors } from "../libraries/Errors.sol"; import { Lockup } from "../types/DataTypes.sol"; import { SablierV2Base } from "./SablierV2Base.sol"; @@ -83,6 +84,9 @@ abstract contract SablierV2Lockup is recipient = _ownerOf(streamId); } + /// @inheritdoc ISablierV2Lockup + function getSender(uint256 streamId) public view virtual override returns (address sender); + /// @inheritdoc ISablierV2Lockup function isCold(uint256 streamId) external view override notNull(streamId) returns (bool result) { Lockup.Status status = _statusOf(streamId); @@ -209,7 +213,7 @@ abstract contract SablierV2Lockup is // 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 { } + try ISablierV2Recipient(recipient).onLockupStreamRenounced(streamId) { } catch { } } } @@ -277,6 +281,9 @@ abstract contract SablierV2Lockup is revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount); } + // Retrieve the sender from storage. + address sender = getSender(streamId); + // Effects and Interactions: make the withdrawal. _withdraw(streamId, to, amount); @@ -284,7 +291,19 @@ abstract contract SablierV2Lockup is // 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({ + try ISablierV2Recipient(recipient).onLockupStreamWithdrawn({ + streamId: streamId, + caller: msg.sender, + to: to, + amount: amount + }) { } catch { } + } + + // Interactions: if `msg.sender` is not the sender and the sender 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 != sender && sender.code.length > 0) { + try ISablierV2Sender(sender).onLockupStreamWithdrawn({ streamId: streamId, caller: msg.sender, to: to, diff --git a/src/interfaces/hooks/ISablierV2LockupRecipient.sol b/src/interfaces/hooks/ISablierV2Recipient.sol similarity index 87% rename from src/interfaces/hooks/ISablierV2LockupRecipient.sol rename to src/interfaces/hooks/ISablierV2Recipient.sol index 2e5e3c04b..268f04238 100644 --- a/src/interfaces/hooks/ISablierV2LockupRecipient.sol +++ b/src/interfaces/hooks/ISablierV2Recipient.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.19; -/// @title ISablierV2LockupRecipient +/// @title ISablierV2Recipient /// @notice Interface for recipient contracts capable of reacting to cancellations, renouncements, and withdrawals. /// @dev Implementation of this interface is optional. If a recipient contract doesn't implement this /// interface or implements it partially, function execution will not revert. -interface ISablierV2LockupRecipient { +interface ISablierV2Recipient { /// @notice Responds to sender-triggered cancellations. /// /// @dev Notes: @@ -17,7 +17,7 @@ interface ISablierV2LockupRecipient { /// 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( + function onLockupStreamCanceled( uint256 streamId, address sender, uint128 senderAmount, @@ -31,7 +31,7 @@ interface ISablierV2LockupRecipient { /// - This function may revert, but the Sablier contract will ignore the revert. /// /// @param streamId The id of the renounced stream. - function onStreamRenounced(uint256 streamId) external; + function onLockupStreamRenounced(uint256 streamId) external; /// @notice Responds to withdrawals triggered by either the stream's sender or an approved third party. /// @@ -42,5 +42,5 @@ interface ISablierV2LockupRecipient { /// @param caller The original `msg.sender` address that triggered the withdrawal. /// @param to The address receiving the withdrawn assets. /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. - function onStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external; + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external; } diff --git a/src/interfaces/hooks/ISablierV2Sender.sol b/src/interfaces/hooks/ISablierV2Sender.sol new file mode 100644 index 000000000..6e8220b93 --- /dev/null +++ b/src/interfaces/hooks/ISablierV2Sender.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19; + +/// @title ISablierV2Sender +/// @notice Interface for sender contracts capable of reacting to withdrawals. +/// @dev Implementation of this interface is optional. If a sender contract doesn't implement this +/// interface or implements it partially, function execution will not revert. +interface ISablierV2Sender { + /// @notice Responds to withdrawals triggered by either the stream's recipient or an approved third party. + /// + /// @dev Notes: + /// - This function may revert, but the Sablier contract will ignore the revert. + /// + /// @param streamId The id of the stream being withdrawn from. + /// @param caller The original `msg.sender` address that triggered the withdrawal. + /// @param to The address receiving the withdrawn assets. + /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external; +} diff --git a/test/Base.t.sol b/test/Base.t.sol index 7d24c7ba1..bc26e18ff 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -16,6 +16,7 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; import { Noop } from "./mocks/Noop.sol"; import { GoodRecipient } from "./mocks/hooks/GoodRecipient.sol"; +import { GoodSender } from "./mocks/hooks/GoodSender.sol"; import { Assertions } from "./utils/Assertions.sol"; import { Calculations } from "./utils/Calculations.sol"; import { Constants } from "./utils/Constants.sol"; @@ -41,6 +42,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi ERC20 internal dai; Defaults internal defaults; GoodRecipient internal goodRecipient; + GoodSender internal goodSender; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; ISablierV2NFTDescriptor internal nftDescriptor; @@ -55,12 +57,14 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi // Deploy the base test contracts. dai = new ERC20("Dai Stablecoin", "DAI"); goodRecipient = new GoodRecipient(); + goodSender = new GoodSender(); noop = new Noop(); usdt = new ERC20MissingReturn("Tether USD", "USDT", 6); // Label the base test contracts. vm.label({ account: address(dai), newLabel: "DAI" }); vm.label({ account: address(goodRecipient), newLabel: "Good Recipient" }); + vm.label({ account: address(goodSender), newLabel: "Good Sender" }); vm.label({ account: address(nftDescriptor), newLabel: "NFT Descriptor" }); vm.label({ account: address(noop), newLabel: "Noop" }); vm.label({ account: address(usdt), newLabel: "USDT" }); diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index bdcd271d8..4d5179717 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -5,7 +5,9 @@ import { Errors } from "src/libraries/Errors.sol"; import { Base_Test } from "../Base.t.sol"; import { ReentrantRecipient } from "../mocks/hooks/ReentrantRecipient.sol"; +import { ReentrantSender } from "../mocks/hooks/ReentrantSender.sol"; import { RevertingRecipient } from "../mocks/hooks/RevertingRecipient.sol"; +import { RevertingSender } from "../mocks/hooks/RevertingSender.sol"; /// @notice Common logic needed by all integration tests, both concrete and fuzz tests. abstract contract Integration_Test is Base_Test { @@ -14,7 +16,9 @@ abstract contract Integration_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ ReentrantRecipient internal reentrantRecipient = new ReentrantRecipient(); + ReentrantSender internal reentrantSender = new ReentrantSender(); RevertingRecipient internal revertingRecipient = new RevertingRecipient(); + RevertingSender internal revertingSender = new RevertingSender(); /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION @@ -43,7 +47,9 @@ abstract contract Integration_Test is Base_Test { /// @dev Labels the most relevant contracts. function labelContracts() internal { vm.label({ account: address(reentrantRecipient), newLabel: "Reentrant Lockup Recipient" }); + vm.label({ account: address(reentrantSender), newLabel: "Reentrant Lockup Sender" }); vm.label({ account: address(revertingRecipient), newLabel: "Reverting Lockup Recipient" }); + vm.label({ account: address(revertingSender), newLabel: "Reverting Lockup Sender" }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/integration/concrete/lockup/cancel/cancel.t.sol index 616e864ee..b572364c0 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/integration/concrete/lockup/cancel/cancel.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.19 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2LockupRecipient } from "src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup } from "src/types/DataTypes.sol"; @@ -144,7 +144,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I vm.expectCall( address(noop), abi.encodeCall( - ISablierV2LockupRecipient.onStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) ) ); @@ -177,7 +177,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I vm.expectCall( address(revertingRecipient), abi.encodeCall( - ISablierV2LockupRecipient.onStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) ) ); @@ -211,7 +211,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I vm.expectCall( address(reentrantRecipient), abi.encodeCall( - ISablierV2LockupRecipient.onStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) ) ); @@ -249,7 +249,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I vm.expectCall( address(goodRecipient), abi.encodeCall( - ISablierV2LockupRecipient.onStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) ) ); diff --git a/test/integration/concrete/lockup/renounce/renounce.t.sol b/test/integration/concrete/lockup/renounce/renounce.t.sol index 7340dc66b..3f7d871cc 100644 --- a/test/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/integration/concrete/lockup/renounce/renounce.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.19 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2LockupRecipient } from "src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; @@ -126,7 +126,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup uint256 streamId = createDefaultStreamWithRecipient(address(noop)); // Expect a call to the hook. - vm.expectCall(address(noop), abi.encodeCall(ISablierV2LockupRecipient.onStreamRenounced, (streamId))); + vm.expectCall(address(noop), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId))); // Renounce the stream. lockup.renounce(streamId); @@ -154,7 +154,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup // Expect a call to the hook. vm.expectCall( - address(revertingRecipient), abi.encodeCall(ISablierV2LockupRecipient.onStreamRenounced, (streamId)) + address(revertingRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId)) ); // Renounce the stream. @@ -184,7 +184,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup // Expect a call to the hook. vm.expectCall( - address(reentrantRecipient), abi.encodeCall(ISablierV2LockupRecipient.onStreamRenounced, (streamId)) + address(reentrantRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId)) ); // Renounce the stream. @@ -214,7 +214,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); // Expect a call to the hook. - vm.expectCall(address(goodRecipient), abi.encodeCall(ISablierV2LockupRecipient.onStreamRenounced, (streamId))); + vm.expectCall(address(goodRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId))); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index fbbeca2f6..d4c405e84 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -2,7 +2,8 @@ pragma solidity >=0.8.19 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2LockupRecipient } from "src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; +import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup } from "src/types/DataTypes.sol"; @@ -135,7 +136,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr _; } - function test_Withdraw_CallerRecipient() + function test_Withdraw_SenderNotContract() external whenNotDelegateCalled givenNotNull @@ -144,19 +145,153 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenCallerRecipient { + test_Withdraw_CallerRecipient(defaultStreamId, users.sender); + } + + modifier givenSenderContract() { + _; + } + + function test_Withdraw_SenderDoesNotImplementHook() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenCallerAuthorized + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenCallerRecipient + givenSenderContract + { + // Create the stream with a noop contract as the stream's sender. + uint256 streamId = createDefaultStreamWithSender(address(noop)); + + test_Withdraw_CallerRecipient(streamId, address(noop)); + } + + modifier givenSenderImplementsHook() { + _; + } + + function test_Withdraw_ReetrancySender() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenCallerAuthorized + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenCallerRecipient + givenSenderContract + givenSenderImplementsHook + { + // Create the stream with a reentrant contract as the stream's sender. + uint256 streamId = createDefaultStreamWithSender(address(reentrantSender)); + // Simulate the passage of time. vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - // Make Alice the `to` address in this test. - address to = users.alice; + // Halve the withdraw amount so that the recipient can re-entry and make another withdrawal. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT() / 2; + + // Expect a call to the hook. + vm.expectCall( + address(reentrantSender), + abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) + ) + ); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: to, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + + // Assert that the stream's status is still "STREAMING". + Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status expectedStatus = Lockup.Status.STREAMING; + assertEq(actualStatus, expectedStatus); // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 expectedWithdrawnAmount = withdrawAmount; + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + } + + modifier whenNoSenderReentrancy() { + _; + } + + function test_Withdraw_RevertingSender() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenCallerAuthorized + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenCallerRecipient + givenSenderContract + givenSenderImplementsHook + whenNoSenderReentrancy + { + // Create the stream with a contract as the stream's sender. + uint256 streamId = createDefaultStreamWithSender(address(revertingSender)); + + test_Withdraw_CallerRecipient(streamId, address(revertingSender)); + } + + modifier whenSenderDoesNotRevert() { + _; + } + + function test_Withdraw_GoodSender() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenCallerAuthorized + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenCallerRecipient + givenSenderContract + givenSenderImplementsHook + whenNoSenderReentrancy + whenSenderDoesNotRevert + { + // Create the stream with a contract as the stream's sender. + uint256 streamId = createDefaultStreamWithSender(address(goodSender)); + + test_Withdraw_CallerRecipient(streamId, address(goodSender)); + } + + function test_Withdraw_CallerRecipient(uint256 streamId, address sender) internal { + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the hook if the sender is a contract. + if (sender.code.length > 0) { + vm.expectCall( + address(sender), + abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) + ) + ); + } + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } @@ -242,36 +377,29 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNoOverdraw whenCallerSender givenEndTimeInTheFuture - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - whenNoRecipientReentrancy { - // Create the stream with a contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); - // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(defaultStreamId); // Set the withdraw amount to the withdrawable amount. - uint128 withdrawAmount = lockup.withdrawableAmountOf(streamId); + uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); // Assert that the stream's status is "DEPLETED". - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.DEPLETED; assertEq(actualStatus, expectedStatus); // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); // Assert that the NFT has not been burned. - address actualNFTowner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = address(goodRecipient); + address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -288,33 +416,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr givenEndTimeInTheFuture whenStreamHasNotBeenCanceled { - // Set the withdraw amount to the streamed amount. - uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); - - // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: withdrawAmount }); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(lockup) }); - emit WithdrawFromLockupStream({ - streamId: defaultStreamId, - to: users.recipient, - asset: dai, - amount: withdrawAmount - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); - - // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); - Lockup.Status expectedStatus = Lockup.Status.STREAMING; - assertEq(actualStatus, expectedStatus); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = withdrawAmount; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + test_Withdraw(defaultStreamId, users.recipient); } modifier givenRecipientContract() { @@ -335,30 +437,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenStreamHasNotBeenCanceled givenRecipientContract { - // Create the stream with a no-op contract as the stream's recipient. + // Create the stream with a noop contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(noop)); - // Expect a call to the hook. - vm.expectCall( - address(noop), - abi.encodeCall( - ISablierV2LockupRecipient.onStreamWithdrawn, - (streamId, users.sender, address(noop), defaults.WITHDRAW_AMOUNT()) - ) - ); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(noop), amount: defaults.WITHDRAW_AMOUNT() }); - - // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.STREAMING; - assertEq(actualStatus, expectedStatus); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); - uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + test_Withdraw(streamId, address(noop)); } modifier givenRecipientImplementsHook() { @@ -383,27 +465,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Create the stream with a reverting contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(revertingRecipient)); - // Expect a call to the hook. - vm.expectCall( - address(revertingRecipient), - abi.encodeCall( - ISablierV2LockupRecipient.onStreamWithdrawn, - (streamId, users.sender, address(revertingRecipient), defaults.WITHDRAW_AMOUNT()) - ) - ); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(revertingRecipient), amount: defaults.WITHDRAW_AMOUNT() }); - - // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.STREAMING; - assertEq(actualStatus, expectedStatus); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); - uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + test_Withdraw(streamId, address(revertingRecipient)); } modifier whenRecipientDoesNotRevert() { @@ -436,7 +498,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.expectCall( address(reentrantRecipient), abi.encodeCall( - ISablierV2LockupRecipient.onStreamWithdrawn, + ISablierV2Recipient.onLockupStreamWithdrawn, (streamId, users.sender, address(reentrantRecipient), withdrawAmount) ) ); @@ -479,34 +541,35 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Create the stream with a contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); - // Set the withdraw amount to the streamed amount. - uint128 withdrawAmount = lockup.streamedAmountOf(streamId); + test_Withdraw(streamId, address(goodRecipient)); + } - // Expect the assets to be transferred to the recipient contract. - expectCallToTransfer({ to: address(goodRecipient), amount: withdrawAmount }); + function test_Withdraw(uint256 streamId, address recipient) internal { + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the hook. - vm.expectCall( - address(goodRecipient), - abi.encodeCall( - ISablierV2LockupRecipient.onStreamWithdrawn, - (streamId, users.sender, address(goodRecipient), withdrawAmount) - ) - ); + // Expect the assets to be transferred to the recipient contract. + expectCallToTransfer({ to: address(recipient), amount: withdrawAmount }); + + // Expect a call to the hook if the recipient is a contract. + if (recipient.code.length > 0) { + vm.expectCall( + address(recipient), + abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, users.sender, address(recipient), withdrawAmount) + ) + ); + } // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit WithdrawFromLockupStream({ - streamId: streamId, - to: address(goodRecipient), - asset: dai, - amount: withdrawAmount - }); + emit WithdrawFromLockupStream({ streamId: streamId, to: address(recipient), asset: dai, amount: withdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipient), amount: withdrawAmount }); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.tree b/test/integration/concrete/lockup/withdraw/withdraw.tree index c36b88582..314fa95e1 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.tree +++ b/test/integration/concrete/lockup/withdraw/withdraw.tree @@ -25,49 +25,73 @@ withdraw.t.sol ├── when the withdraw amount overdraws │ └── it should revert └── when the withdraw amount does not overdraw - ├── when the caller is the recipient - │ ├── it should make the withdrawal - │ └── it should update the withdrawn amount - ├── when the caller is an approved third party - │ ├── it should make the withdrawal - │ └── it should update the withdrawn amount - └── when the caller is the sender - ├── given the end time is not in the future + ├── when the caller is the recipient + │ ├── given the sender is not a contract + │ │ ├── it should make the withdrawal + │ │ └── it should update the withdrawn amount + │ └── given the sender is a contract + │ ├── given the sender does not implement the hook + │ │ ├── it should make the withdrawal + │ │ ├── it should update the withdrawn amount + │ │ ├── it should call the sender hook + │ │ └── it should ignore the revert + │ └── given the sender implements the hook + │ ├── when the sender reverts + │ │ ├── it should make the withdrawal + │ │ ├── it should update the withdrawn amount + │ │ ├── it should call the sender hook + │ │ └── it should ignore the revert + │ └── when the sender does not revert + │ ├── when there is reentrancy + │ │ ├── it should make multiple withdrawals + │ │ ├── it should update the withdrawn amounts + │ │ └── it should call the sender hooks + │ └── when there is no reentrancy + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ ├── it should call the sender hook + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── when the caller is an approved third party │ ├── it should make the withdrawal - │ ├── it should mark the stream as depleted - │ └── it should make the stream not cancelable - └── given the end time is in the future - ├── given the stream has been canceled + │ └── it should update the withdrawn amount + └── when the caller is the sender + ├── given the end time is not in the future │ ├── it should make the withdrawal │ ├── it should mark the stream as depleted - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ ├── it should emit a {MetadataUpdate} event - │ └── it should emit a {WithdrawFromLockupStream} event - └── given the stream has not been canceled - ├── given the recipient is not a contract - │ └── it should make the withdrawal - │ └── it should update the withdrawn amount - └── given the recipient is a contract - ├── given the recipient does not implement the hook - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── given the recipient implements the hook - ├── when the recipient reverts + │ └── it should make the stream not cancelable + └── given the end time is in the future + ├── given the stream has been canceled + │ ├── it should make the withdrawal + │ ├── it should mark the stream as depleted + │ ├── it should update the withdrawn amount + │ ├── it should call the recipient hook + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── given the stream has not been canceled + ├── given the recipient is not a contract + │ └── it should make the withdrawal + │ └── it should update the withdrawn amount + └── given the recipient is a contract + ├── given the recipient does not implement the hook │ ├── it should make the withdrawal │ ├── it should update the withdrawn amount │ ├── it should call the recipient hook │ └── it should ignore the revert - └── when the recipient does not revert - ├── when there is reentrancy - │ ├── it should make multiple withdrawals - │ ├── it should update the withdrawn amounts - │ └── it should call the recipient hooks - └── when there is no reentrancy - ├── it should make the withdrawal - ├── it should update the withdrawn amount - ├── it should call the recipient hook - ├── it should emit a {MetadataUpdate} event - └── it should emit a {WithdrawFromLockupStream} event + └── given the recipient implements the hook + ├── when the recipient reverts + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ ├── it should call the recipient hook + │ └── it should ignore the revert + └── when the recipient does not revert + ├── when there is reentrancy + │ ├── it should make multiple withdrawals + │ ├── it should update the withdrawn amounts + │ └── it should call the recipient hooks + └── when there is no reentrancy + ├── it should make the withdrawal + ├── it should update the withdrawn amount + ├── it should call the recipient hook + ├── it should emit a {MetadataUpdate} event + └── it should emit a {WithdrawFromLockupStream} event diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index c2cd2f1cc..4e956be9c 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -7,7 +7,7 @@ contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integrat function test_GenerateAccentColor() external { // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); - string memory expectedColor = "hsl(268,54%,64%)"; + string memory expectedColor = "hsl(302,69%,44%)"; assertEq(actualColor, expectedColor, "accentColor"); } } diff --git a/test/mocks/hooks/GoodRecipient.sol b/test/mocks/hooks/GoodRecipient.sol index e4f8aecf3..2a72f2eaa 100644 --- a/test/mocks/hooks/GoodRecipient.sol +++ b/test/mocks/hooks/GoodRecipient.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.19; -import { ISablierV2LockupRecipient } from "../../../src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; -contract GoodRecipient is ISablierV2LockupRecipient { - function onStreamCanceled( +contract GoodRecipient is ISablierV2Recipient { + function onLockupStreamCanceled( uint256 streamId, address sender, uint128 senderAmount, @@ -19,11 +19,11 @@ contract GoodRecipient is ISablierV2LockupRecipient { recipientAmount; } - function onStreamRenounced(uint256 streamId) external pure { + function onLockupStreamRenounced(uint256 streamId) external pure { streamId; } - function onStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { streamId; caller; to; diff --git a/test/mocks/hooks/GoodSender.sol b/test/mocks/hooks/GoodSender.sol new file mode 100644 index 000000000..eb8f09e79 --- /dev/null +++ b/test/mocks/hooks/GoodSender.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19; + +import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; + +contract GoodSender is ISablierV2Sender { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { + streamId; + caller; + to; + amount; + } +} diff --git a/test/mocks/hooks/ReentrantRecipient.sol b/test/mocks/hooks/ReentrantRecipient.sol index dfe7bcfb3..551e6ed6e 100644 --- a/test/mocks/hooks/ReentrantRecipient.sol +++ b/test/mocks/hooks/ReentrantRecipient.sol @@ -2,10 +2,10 @@ pragma solidity >=0.8.19; import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2LockupRecipient } from "../../../src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; -contract ReentrantRecipient is ISablierV2LockupRecipient { - function onStreamCanceled( +contract ReentrantRecipient is ISablierV2Recipient { + function onLockupStreamCanceled( uint256 streamId, address sender, uint128 senderAmount, @@ -20,11 +20,11 @@ contract ReentrantRecipient is ISablierV2LockupRecipient { ISablierV2Lockup(msg.sender).cancel(streamId); } - function onStreamRenounced(uint256 streamId) external { + function onLockupStreamRenounced(uint256 streamId) external { ISablierV2Lockup(msg.sender).renounce(streamId); } - function onStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external { streamId; caller; to; diff --git a/test/mocks/hooks/ReentrantSender.sol b/test/mocks/hooks/ReentrantSender.sol new file mode 100644 index 000000000..4eaf833d4 --- /dev/null +++ b/test/mocks/hooks/ReentrantSender.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19; + +import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; + +contract ReentrantSender is ISablierV2Sender { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external { + streamId; + caller; + to; + amount; + ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), amount); + } +} diff --git a/test/mocks/hooks/RevertingRecipient.sol b/test/mocks/hooks/RevertingRecipient.sol index 0593e08fb..d9255d12e 100644 --- a/test/mocks/hooks/RevertingRecipient.sol +++ b/test/mocks/hooks/RevertingRecipient.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.19; -import { ISablierV2LockupRecipient } from "../../../src/interfaces/hooks/ISablierV2LockupRecipient.sol"; +import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; -contract RevertingRecipient is ISablierV2LockupRecipient { - function onStreamCanceled( +contract RevertingRecipient is ISablierV2Recipient { + function onLockupStreamCanceled( uint256 streamId, address sender, uint128 senderAmount, @@ -20,12 +20,12 @@ contract RevertingRecipient is ISablierV2LockupRecipient { revert("You shall not pass"); } - function onStreamRenounced(uint256 streamId) external pure { + function onLockupStreamRenounced(uint256 streamId) external pure { streamId; revert("You shall not pass"); } - function onStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { streamId; caller; to; diff --git a/test/mocks/hooks/RevertingSender.sol b/test/mocks/hooks/RevertingSender.sol new file mode 100644 index 000000000..3af539484 --- /dev/null +++ b/test/mocks/hooks/RevertingSender.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.19; + +import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; + +contract RevertingSender is ISablierV2Sender { + function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { + streamId; + caller; + to; + amount; + revert("You shall not pass"); + } +} diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 213dddbe1..0d9780746 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -27,9 +27,9 @@ contract Precompiles { bytes public constant BYTECODE_COMPTROLLER = hex"60803461009857601f6102d538819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361022190816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816375829def1461014c57508063b5b3ca2c146100ac578063dcf844a7146100765763f851a4401461004e57600080fd5b346100725781600319360112610072576001600160a01b0360209254169051908152f35b5080fd5b503461007257602036600319011261007257806020926001600160a01b0361009c6101f9565b1681526001845220549051908152f35b50346100725780600319360112610072576100c56101f9565b602435906001600160a01b0390818554163381036101245750907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526001602052808520928084549455815193845260208401523392a380f35b84516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b83903461007257602036600319011261007257600435906001600160a01b03908183168093036101f55783549182163381036101d25750507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6331b339a960e21b82526001600160a01b03166004820152336024820152604490fd5b8380fd5b600435906001600160a01b038216820361020f57565b600080fdfea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0346200046e57601f62005be438819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a05260016009556040516157509081620004948239608051816132f7015260a051818181610f7a01526134180152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126f55750806306fdde0314612630578063081812fc14612612578063095ea7b31461247e5780631400ecec146123d957806316844456146121155780631c1cdd4c146120af5780631e99d5691461209157806323b872dd1461206857806339a73c031461202557806340e58ee514611dd1578063425d30dd14611db357806342842e0e14611d6357806342966c6814611bd35780634857501f14611b5d5780634869e12d14611b215780635fe3b56714611afa5780636352211e14611acb5780636d0cee7514611a7357806370a08231146119c957806375829def146119375780637cad6cd1146118655780637de6b1db146116555780638659c2701461135c578063894e9a0d146110ef5780638bad38dd146110735780638f69b99314610ff05780639067b67714610f9d5780639188ec8414610f6257806395d89b4114610e52578063a22cb46514610d81578063a2ffb89714610c9f578063a6202bf214610b96578063a80fc07114610b41578063ad35efd414610ade578063b256456914610ac0578063b637b86514610a60578063b88d4fde146109d7578063b8a3be66146109a0578063b971302a1461094e578063bc063e1a1461092b578063bc2be1be146108d8578063c156a11d14610820578063c33cd35e146106c1578063c87b56dd1461058e578063cc364f48146104f4578063d4dbd20b1461049f578063d511609f14610450578063d975dfed14610403578063e985e9c5146103ac578063ea5ead191461037e578063eac8f5b814610312578063f590c176146102ea578063f851a440146102c35763fdd46d601461027c57600080fd5b346102be5760603660031901126102be57610295612822565b6044356001600160801b03811681036102be576102bc916102b46132ed565b6004356131da565b005b600080fd5b346102be5760003660031901126102be5760206001600160a01b0360005416604051908152f35b346102be5760203660031901126102be576020610308600435612e21565b6040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102be5760403660031901126102be576102bc60043561039d612822565b6103a6826140c2565b91612e52565b346102be5760403660031901126102be576103c561280c565b6103cd612822565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916140c2565b6001600160801b0360405191168152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602060026040600020015460801c604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102be5760203660031901126102be57600435600060206040516105188161295c565b828152015280600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526040806000205464ffffffffff82519161055b8361295c565b818160a01c16835260c81c16602082015261058c825180926020908164ffffffffff91828151168552015116910152565bf35b346102be576020806003193601126102be57600435906105cc6105c78360005260056020526001600160a01b0360406000205416151590565b612bdb565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106b55760009261063c575b506106386040519282849384528301906127e7565b0390f35b9091503d806000833e61064f81836129a9565b81019082818303126102be5780519067ffffffffffffffff82116102be570181601f820112156102be578051610684816129cb565b9261069260405194856129a9565b8184528482840101116102be576106ae918480850191016127c4565b9082610623565b6040513d6000823e3d90fd5b346102be57600319602036820181136102be5760043567ffffffffffffffff928382116102be576101409082360301126102be576106fd6132ed565b6040519261070a8461293f565b61071682600401612838565b845261072460248301612a69565b602085015261073560448301612916565b604085015261074660648301612916565b91606092606086015261075b60848201612838565b608086015261076c60a482016129e7565b60a086015261077d60c48201612838565b60c086015261078f3660e48301612b04565b60e08601526101248101359182116102be5701366023820112156102be576004810135926107bc84612a51565b936107ca60405195866129a9565b80855260246060602087019202840101923684116102be57602401905b838210610808576020610800888861010082015261336a565b604051908152f35b8285916108153685612a7b565b8152019101906107e7565b346102be5760403660031901126102be5760043561083c612822565b906108456132ed565b80600052600b60205260ff60016040600020015460a81c1615610367578060005260056020526001600160a01b0360406000205416918233036108b5576102bc9261088f836140c2565b6001600160801b0381166108a4575b50613ddb565b6108af908285612e52565b8461089e565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102be5760003660031901126102be57602060405167016345785d8a00008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be57600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102be5760803660031901126102be576109f061280c565b6109f8612822565b6064359167ffffffffffffffff83116102be57366023840112156102be57826004013591610a25836129cb565b92610a3360405194856129a9565b80845236602482870101116102be5760208160009260246102bc9801838801378501015260443591612d8b565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052610638610aac6004604060002001612cc4565b6040519182916020835260208301906128b2565b346102be5760203660031901126102be576020610308600435612d54565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757610b1890613c75565b6040516005821015610b2b576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102be5760203660031901126102be57610baf61280c565b6001600160a01b038060005416338103610c7657508116908160005260026020526001600160801b0360406000205416908115610c455781610c179184600052600260205260406000206fffffffffffffffffffffffffffffffff198154169055339061405a565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102be5760603660031901126102be5767ffffffffffffffff6004358181116102be57610cd1903690600401612881565b9190610cdb612822565b916044359081116102be57610cf4903690600401612881565b92610cfd6132ed565b838503610d4a5760005b858110610d1057005b80610d44610d216001938988612c4b565b3584610d36610d31858b8a612c4b565b612af0565b91610d3f6132ed565b6131da565b01610d07565b60448585604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102be5760403660031901126102be57610d9a61280c565b602435908115158092036102be576001600160a01b031690813314610e0e57336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102be5760003660031901126102be5760405160006004549060018260011c9160018416918215610f58575b6020948585108414610f42578587948686529182600014610f22575050600114610ec5575b50610eb1925003836129a9565b6106386040519282849384528301906127e7565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610f0a575050610eb1935082010185610ea4565b80548389018501528794508693909201918101610ef3565b60ff191685820152610eb195151560051b8501019250879150610ea49050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610e7f565b346102be5760003660031901126102be5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761102a90613c75565b600581101580610b2b5760028214908115611066575b8115611054575b6020826040519015158152f35b9050610b2b5760046020911482611047565b5050600381146000611040565b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c76575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102be5760203660031901126102be5760606101406040516111118161298c565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152611155612c71565b6101208201520152600435600052600b60205260ff60016040600020015460a81c161561134457600435600052600b602052604060002061123860046040519261119e8461298c565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015261122c60028201612c90565b61012085015201612cc4565b610140820152611249600435613c75565b906005821015610b2b5760026101409214611338575b610638604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261132461012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c08301906128b2565b6000606082015261125f565b602460405162b8e7e760e51b81526004356004820152fd5b346102be576020806003193601126102be5760043567ffffffffffffffff81116102be5761138e903690600401612881565b906113976132ed565b6000915b8083106113a457005b6113af838284612c4b565b35926113b96132ed565b6113c284612ba4565b156113df5760248460405190634a5541ef60e01b82526004820152fd5b6113eb84929394612e21565b61163d5761140f82600052600b6020526001600160a01b0360406000205416331490565b156108b55761141d82613282565b82600052600b8087526114366002604060002001612c90565b906001600160801b0392838351168482161015611625578560005281895260ff60406000205460f01c161561160d57906114a482858b61149a7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509683895116612a38565b9601511690612a38565b9580600052818a526040600020938a855498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617875560038882169788156115f3575b0197831697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a16958691600584528b604060002054169687945260019b8c6040600020015416946115408b858861405a565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b6115a0575b505050505001919061139b565b813b156102be576000608492819560405197889687956372eba20360e01b875260048701526024860152604485015260648401525af16115e4575b80808080611593565b6115ed90612978565b856115db565b60018101600160a01b60ff60a01b198254161790556114ec565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102be576020806003193601126102be57600435906116736132ed565b81600052600b815260ff60016040600020015460a81c161561184e5761169882613c75565b6005811015610b2b57600481036116c15760248360405190634a5541ef60e01b82526004820152fd5b600381036116e1576024836040519063fe19f19f60e01b82526004820152fd5b6002146118365761170882600052600b6020526001600160a01b0360406000205416331490565b156108b55781600052600b815260ff60406000205460f01c161561181e5781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b6117af575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102be57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f341a0bd90000000000000000000000000000000000000000000000000000000083528760048401525af1156117835761181890612978565b83611783565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c765750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116119215760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102be5760203660031901126102be5761195061280c565b6000546001600160a01b03808216923384036119a2576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102be5760203660031901126102be576001600160a01b036119ea61280c565b168015611a095760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57600435611aaa6105c78260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be576020611ae9600435612c26565b6001600160a01b0360405191168152f35b346102be5760003660031901126102be5760206001600160a01b0360015416604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f602091613fdf565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576000611b9982613c75565b6005811015610b2b57600203611bb7575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611baa565b346102be5760203660031901126102be57600435611bef6132ed565b611bf881612ba4565b15611d3257611c0681613f76565b15611d1257611c1481612c26565b611c1d82612d54565b159081611d09575b81611cf6575b50611cde57602081611c5d7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612c26565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611c2b565b60009150611c25565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102be57611d713661284c565b60405191602083019383851067ffffffffffffffff861117611d9d576102bc9460405260008452612d8b565b634e487b7160e01b600052604160045260246000fd5b346102be5760203660031901126102be576020610308600435612ba4565b346102be576020806003193601126102be5760043590611def6132ed565b611df882612ba4565b15611e155760248260405190634a5541ef60e01b82526004820152fd5b611e1e82612e21565b61163d57611e4282600052600b6020526001600160a01b0360406000205416331490565b156108b557611e5082613282565b9180600052600b8252611e696002604060002001612c90565b906001600160801b03938483511685821610156118365781600052600b845260ff60406000205460f01c161561181e57808585611eac611eb69483885116612a38565b9501511690612a38565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716178755600388861697881561200b575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b87526001604060002001541694611f948d858861405a565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b611fc657005b813b156102be576000608492819560405197889687956372eba20360e01b875260048701526024860152604485015260648401525af161200257005b6102bc90612978565b60018101600160a01b60ff60a01b19825416179055611f1f565b346102be5760203660031901126102be576001600160a01b0361204661280c565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102be576102bc6120793661284c565b9161208c6120878433613cfc565b612b33565b613ddb565b346102be5760003660031901126102be576020600954604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576120e990613c75565b6005811015610b2b57806020911590811561210a575b506040519015158152f35b6001915014826120ff565b346102be57602060031981813601126102be576004359067ffffffffffffffff908183116102be57610120833603918201126102be576121536132ed565b61010483013590602219018112156102be578201916004830135928284116102be57602481016060916060860280360383136102be5760249061219588612a51565b976121a3604051998a6129a9565b8852888801920101913683116102be57905b878383106123c2578787878251906121cc82612a51565b916121da60405193846129a9565b808352601f196121e982612a51565b018660005b8281106123ac5750505064ffffffffff90814216946001600160801b03968761221682613349565b515116828a61222484613349565b510151168580604061223586613349565b510151168a0116906040519261224a84612923565b83528b830152604082015261225e87613349565b5261226886613349565b506001938660015b8a8c87831061232b57908b846001600160a01b038c60a4810135828116908190036102be57610800956122eb9561231b946122ad60248601612acf565b6122b960448701612acf565b6122c560648801612adc565b916122d288600401612adc565b94846122e060848b01612af0565b966040519d8e61293f565b168c528d8c0152151560408b0152151560608a01521660808801521660a086015260c085015260c4369101612b04565b60e083015261010082015261336a565b88938580604061235f8b8661234f8a8e9a612346828d613356565b5151169a613356565b5101511694600019890190613356565b51015116816040612370888c613356565b510151160116916040519361238485612923565b84528301526040820152612398828b613356565b526123a3818a613356565b50018790612270565b6123b4612c71565b8282880101520187906121ee565b84916123ce3685612a7b565b8152019101906121b5565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675760209060009080600052600b8352604060002060ff815460f01c168061246c575b612443575b50506001600160801b0360405191168152f35b61246592506001600160801b03600261245f9201541691613282565b90612a38565b8280612430565b5060ff600182015460a01c161561242b565b346102be5760403660031901126102be5761249761280c565b602435906001600160a01b0380806124ae85612c26565b169216918083146125a857803314908115612583575b5015612519578260005260076020526040600020826001600160a01b03198254161790556124f183612c26565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff60406000205416846124c4565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be576020611ae96004356129fb565b346102be5760003660031901126102be5760405160006003549060018260011c91600184169182156126eb575b6020948585108414610f42578587948686529182600014610f2257505060011461268e5750610eb1925003836129a9565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106126d3575050610eb1935082010185610ea4565b805483890185015287945086939092019181016126bc565b92607f169261265d565b346102be5760203660031901126102be57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102be57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561279a575b8115612770575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612769565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612762565b60005b8381106127d75750506000910152565b81810151838201526020016127c7565b90602091612800815180928185528580860191016127c4565b601f01601f1916010190565b600435906001600160a01b03821682036102be57565b602435906001600160a01b03821682036102be57565b35906001600160a01b03821682036102be57565b60609060031901126102be576001600160a01b039060043582811681036102be579160243590811681036102be579060443590565b9181601f840112156102be5782359167ffffffffffffffff83116102be576020808501948460051b0101116102be57565b90815180825260208080930193019160005b8281106128d2575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128c4565b359081151582036102be57565b6060810190811067ffffffffffffffff821117611d9d57604052565b610120810190811067ffffffffffffffff821117611d9d57604052565b6040810190811067ffffffffffffffff821117611d9d57604052565b67ffffffffffffffff8111611d9d57604052565b610160810190811067ffffffffffffffff821117611d9d57604052565b90601f8019910116810190811067ffffffffffffffff821117611d9d57604052565b67ffffffffffffffff8111611d9d57601f01601f191660200190565b35906001600160801b03821682036102be57565b612a1e6105c78260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161192157565b67ffffffffffffffff8111611d9d5760051b60200190565b359064ffffffffff821682036102be57565b91908260609103126102be57604051612a9381612923565b8092612a9e816129e7565b825260208101359067ffffffffffffffff821682036102be576040612aca918193602086015201612a69565b910152565b3580151581036102be5790565b356001600160a01b03811681036102be5790565b356001600160801b03811681036102be5790565b91908260409103126102be57604051612b1c8161295c565b6020808294612b2a81612838565b84520135910152565b15612b3a57565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460a01c1690565b15612be257565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c48811515612bdb565b90565b9190811015612c5b5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190612c7e82612923565b60006040838281528260208201520152565b90604051612c9d81612923565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612cd081612a51565b92604093612ce160405191826129a9565b82815280946020809201926000526020600020906000935b858510612d0857505050505050565b60018481928451612d1881612923565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cf9565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460b01c1690565b90612daf939291612d9f6120878433613cfc565b612daa838383613ddb565b6146f5565b15612db657565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260406000205460f81c90565b929192612e5d6132ed565b612e6681612ba4565b6131c257612e8a81600052600b6020526001600160a01b0360406000205416331490565b918215806131b2575b6108b557600092828452602093600585526001600160a01b039660409388858420541693806131a6575b6131685788811698891561313f576001600160801b0380841693841561310f57612f00612ee98a613fdf565b8a8852600b8c5260028a8920015460801c90612a38565b82811686116130c75750918491612f5f612f2d612f9895600b8e8e8c525260028c8b20015460801c6140ea565b8b8952600b8d5260028b8a200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c90565b90612f7a818d8401511692828c818351169201511690612a38565b161115613098575b888652600b8a526001888720015416928361405a565b88867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d898851868152a4823314158061308e575b612fff575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b823b1561308a5760847ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7979883865195869485937f13375c3b0000000000000000000000000000000000000000000000000000000085528a6004860152336024860152604485015260648401525af161307b575b859481612fd1565b61308490612978565b38613073565b5080fd5b50823b1515612fcc565b888652600b8a5287862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612f82565b88517fa1fb2bbc000000000000000000000000000000000000000000000000000000008152600481018b90526001600160801b03928316602482015291166044820152606490fd5b6024898951907fd2aabcd90000000000000000000000000000000000000000000000000000000082526004820152fd5b600486517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b85896064928751927f5b97ed720000000000000000000000000000000000000000000000000000000084526004840152336024840152166044820152fd5b50838982161415612ebd565b506131bc82613f76565b15612e93565b60249060405190634a5541ef60e01b82526004820152fd5b9291926131e681612ba4565b6131c25761320a81600052600b6020526001600160a01b0360406000205416331490565b91821580613272575b6108b557600092828452602093600585526001600160a01b03966040938885842054169380613266575b6131685788811698891561313f576001600160801b0380841693841561310f57612f00896140c2565b5083898216141561323d565b5061327c82613f76565b15613213565b64ffffffffff80421682600052600b602052604060002091825482828260a01c1610156132e35760c81c1611156132d15760040154600110156132c857612c48906141d9565b612c4890614105565b6001600160801b039150600201541690565b5050505050600090565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361331f57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c5b5760200190565b8051821015612c5b5760209160051b010190565b906001600160a01b036001541660206001600160a01b0360c0850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106b557600090613c41575b6133eb91506001600160801b0360a08501511690602060e08601510151916143c4565b6001600160801b0381511661010084015164ffffffffff6020860151168215613c175781518015613bed577f00000000000000000000000000000000000000000000000000000000000000008111613bbc575064ffffffffff604061344f84613349565b51015116811015613b655750600090819082815184905b808210613ad2575050505064ffffffffff421664ffffffffff8216811015613a925750506001600160801b0316808203613a5b5750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b0360c083015116600184015490750100000000000000000000000000000000000000000060408501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff000000000000000000000000000000000000000000006060890151151560b01b16921617171760018601556001600160a01b0384511691610100850151926040613581855195600019870190613356565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060208b015160a01b169660c81b169460f01b16911617171717845560005b81811061398b575050600185016009556001600160a01b0360c08301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b0360c0840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036080830151168015613947576136c86136c28760005260056020526001600160a01b0360406000205416151590565b15614503565b6136d186612d54565b158061393e575b80613936575b61391e5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7916137296136c28960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a16137b96001600160a01b0360c0840151166001600160801b0380845116816020860151160116903090339061454e565b6001600160801b03604082015116806138ef575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6138ac6001600160a01b03845116926001600160a01b03608086015116946001600160a01b0360c082015116966138e46138c460408401511515928c606086015115156001600160a01b0360e061010089015194549864ffffffffff6040519a6138588c61295c565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e08801528601906128b2565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613918906001600160a01b0360c0850151166001600160a01b0360e0860151511690339061454e565b386137cd565b60248660405190630da9b01360e01b82526004820152fd5b5060006136de565b508015156136d8565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b61399a81610100860151613356565b519060048601549168010000000000000000831015611d9d5760018301806004890155831015612c5b5760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b16931617171790550161361d565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613af6906001600160801b03613aed8588613356565b515116906140ea565b9364ffffffffff806040613b0a8685613356565b51015116941680851115613b28575060018493019192919092613466565b8385606492604051927f7b0bada8000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613b7684613349565b5101516040517fb4c9e52c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d602011613c6d575b81613c5b602093836129a9565b810103126102be576133eb90516133c8565b3d9150613c4e565b80600052600b602052604060002060ff600182015460a01c16600014613c9c575050600490565b805460f81c613cf5575460a01c64ffffffffff164210613cef57613cbf81613282565b90600052600b6020526001600160801b038060026040600020015416911610600014613cea57600190565b600290565b50600090565b5050600390565b906001600160a01b038080613d1084612c26565b16931691838314938415613d43575b508315613d2d575b50505090565b613d39919293506129fb565b1614388080613d27565b909350600052600860205260406000208260005260205260ff604060002054169238613d1f565b15613d7157565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b90613e049291613dea83612c26565b916001600160a01b03948593848094169687911614613d6a565b1690811580613f0d57613e1684612d54565b159081613f04575b5080613efb575b613ee35791808492613e657ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796602096613e5e85612c26565b1614613d6a565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515613e25565b90501538613e1e565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b60009080825260056020526001600160a01b038060408420541692833314938415613fbb575b50508215613fa957505090565b909150613fb633926129fb565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613f9c565b80600052600b602052613ff86002604060002001612c90565b81600052600b602052604060002060ff600182015460a01c1660001461402b57506001600160801b039150602001511690565b5460f81c61403d5750612c4890613282565b612c4891506001600160801b036040818351169201511690612a38565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611d9d576140c0926040526145b9565b565b612c48906140cf81613fdf565b90600052600b60205260026040600020015460801c90612a38565b9190916001600160801b038080941691160191821161192157565b64ffffffffff61413a600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614888565b91808252600b602052600460408320018054156141c55790829167ffffffffffffffff93526141976020832054828452600b6020526141926001600160801b03968760026040882001541696879360801c1690614978565b6149e6565b9283136141ad5750506141a990614ad0565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b6020526040908181208251936142008561298c565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c16151561010088015261014061429b600461428c60028801612c90565b966101208b0197885201612cc4565b97019187835280876142ad889a613349565b5101511693828288965b161061438c5750916143416141929284888161434698976001600160801b039e8f6142e38b8a51613356565b5151169d8a8f9b602061430067ffffffffffffffff928d51613356565b51015116998483614312848451613356565b51015116965081156143805761433092935051906000190190613356565b5101511680925b0316920316614888565b614978565b92831361435f5750506143598391614ad0565b16011690565b51602001519293928316928416831015915061437b9050575090565b905090565b50505051168092614337565b8094986001600160801b0390816143a48c8851613356565b51511601169801938282808a6143bb898951613356565b510151166142b7565b9092916143cf612c71565b936001600160801b03928381169182156144db5767016345785d8a00008082116144a45780851161446d57506144198561440a8193866155fc565b169460208901958652846155fc565b1691846144306040890194808652828751166140ea565b1610156144575761444984918261445295511690612a38565b91511690612a38565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516144ee81612923565b60008152600060208201526000604082015290565b1561450a57565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611d9d576140c0926040525b6001600160a01b0316906146196040516145d28161295c565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16146136146c5565b916156ab565b80519182159184831561469e575b5050509050156146345750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91938180945001031261308a578201519081151582036146c2575080388084614627565b80fd5b3d156146f0573d906146d6826129cb565b916146e460405193846129a9565b82523d6000602084013e565b606090565b9290803b1561487f5761475f916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906127e7565b03916000968791165af19082908261481e575b50506147f8576147806146c5565b805190816147f35760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614877575b8161483b602093836129a9565b8101031261308a5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036146c25750903880614772565b3d915061482e565b50505050600190565b600160ff1b80821490811561496e575b5061494457600081121561493b576148c1816000035b6000841215614934578360000390614b0c565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148fd57600019911813156148f75790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614b0c565b6148c1816148ae565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614898565b80614993575061498e57670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146149e05750806149b8575050670de0b6b3a764000090565b670de0b6b3a764000081146149dc576149d790614192612c4893614c06565b614d48565b5090565b91505090565b600160ff1b808214908115614ac6575b50614a9c576000811215614a9357614a1f816000035b6000841215614a8c5783600003906155fc565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614a5557600019911813156148f75790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906155fc565b614a1f81614a0c565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386149f6565b60008112614adb5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614bc85782851015614b8c57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614bd6570490565b634e487b7160e01b600052601260045260246000fd5b8015614bd6576ec097ce7bc90715b34b9f10000000000590565b80600080831315614d1757670de0b6b3a764000092838112614cf457506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ce857506706f05b59d3b20000905b848213614cbc5750505050500290565b808391020590671bc16d674ec80000821215614cdb575b831d90614cac565b8091950194831d90614cd3565b93505093925050020290565b6000199392508015614bd6576ec097ce7bc90715b34b9f10000000000591614c27565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614d775768033dd1780914b97114198112613cef57614d6e90600003614d48565b612c4890614bec565b680a688906bd8affffff81136155cb57670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166154ae575b66ff00000000000083166153a6575b65ff000000000083166152a6575b64ff0000000083166151ae575b63ff00000083166150be575b62ff00008316614fd6575b61ff008316614ef6575b60ff8316614e1f575b02911c60bf031c90565b60808316614ee4575b838316614ed2575b60208316614ec0575b60108316614eae575b60088316614e9c575b60048316614e8a575b60028316614e78575b6001831615614e15576801000000000000000102831c614e15565b6801000000000000000102831c614e5d565b6801000000000000000302831c614e54565b6801000000000000000602831c614e4b565b6801000000000000000b02831c614e42565b6801000000000000001602831c614e39565b6801000000000000002c02831c614e30565b6801000000000000005902831c614e28565b6180008316614fc4575b6140008316614fb2575b6120008316614fa0575b6110008316614f8e575b6108008316614f7c575b6104008316614f6a575b6102008316614f58575b610100831615614e0c57680100000000000000b102831c614e0c565b6801000000000000016302831c614f3c565b680100000000000002c602831c614f32565b6801000000000000058c02831c614f28565b68010000000000000b1702831c614f1e565b6801000000000000162e02831c614f14565b68010000000000002c5d02831c614f0a565b680100000000000058b902831c614f00565b6280000083166150ac575b62400000831661509a575b622000008316615088575b621000008316615076575b620800008316615064575b620400008316615052575b620200008316615040575b62010000831615614e02576801000000000000b17202831c614e02565b680100000000000162e402831c615023565b6801000000000002c5c802831c615018565b68010000000000058b9102831c61500d565b680100000000000b172102831c615002565b68010000000000162e4302831c614ff7565b680100000000002c5c8602831c614fec565b6801000000000058b90c02831c614fe1565b6380000000831661519c575b6340000000831661518a575b63200000008316615178575b63100000008316615166575b63080000008316615154575b63040000008316615142575b63020000008316615130575b6301000000831615614df75768010000000000b1721802831c614df7565b6801000000000162e43002831c615112565b68010000000002c5c86002831c615106565b680100000000058b90c002831c6150fa565b6801000000000b17217f02831c6150ee565b680100000000162e42ff02831c6150e2565b6801000000002c5c85fe02831c6150d6565b68010000000058b90bfc02831c6150ca565b6480000000008316615294575b6440000000008316615282575b6420000000008316615270575b641000000000831661525e575b640800000000831661524c575b640400000000831661523a575b6402000000008316615228575b640100000000831615614deb57680100000000b17217f802831c614deb565b68010000000162e42ff102831c615209565b680100000002c5c85fe302831c6151fc565b6801000000058b90bfce02831c6151ef565b68010000000b17217fbb02831c6151e2565b6801000000162e42fff002831c6151d5565b68010000002c5c8601cc02831c6151c8565b680100000058b90c0b4902831c6151bb565b658000000000008316615394575b654000000000008316615382575b652000000000008316615370575b65100000000000831661535e575b65080000000000831661534c575b65040000000000831661533a575b650200000000008316615328575b65010000000000831615614dde576801000000b17218355102831c614dde565b680100000162e430e5a202831c615308565b6801000002c5c863b73f02831c6152fa565b68010000058b90cf1e6e02831c6152ec565b680100000b1721bcfc9a02831c6152de565b68010000162e43f4f83102831c6152d0565b680100002c5c89d5ec6d02831c6152c2565b6801000058b91b5bc9ae02831c6152b4565b6680000000000000831661549c575b6640000000000000831661548a575b66200000000000008316615478575b66100000000000008316615466575b66080000000000008316615454575b66040000000000008316615442575b66020000000000008316615430575b6601000000000000831615614dd05768010000b17255775c0402831c614dd0565b6801000162e525ee054702831c61540f565b68010002c5cc37da949202831c615400565b680100058ba01fb9f96d02831c6153f1565b6801000b175effdc76ba02831c6153e2565b680100162f3904051fa102831c6153d3565b6801002c605e2e8cec5002831c6153c4565b68010058c86da1c09ea202831c6153b5565b67800000000000000083166155ac575b674000000000000000831661559a575b6720000000000000008316615588575b6710000000000000008316615576575b6708000000000000008316615564575b6704000000000000008316615552575b6702000000000000008316615540575b670100000000000000831615614dc157680100b1afa5abcbed6102831c614dc1565b68010163da9fb33356d802831c61551e565b680102c9a3e778060ee702831c61550e565b6801059b0d31585743ae02831c6154fe565b68010b5586cf9890f62a02831c6154ee565b6801172b83c7d517adce02831c6154de565b6801306fe0a31b7152df02831c6154ce565b5077b504f333f9de6484800000000000000000000000000000006154be565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461569a57670de0b6b3a7640000908183101561566357947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9192901561570c57508151156156bf575090565b3b156156c85790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501561571f5750805190602001fd5b6108d49060405191829162461bcd60e51b83526020600484015260248301906127e756fea164736f6c6343000817000a"; + hex"60c0346200046e57601f62005ee938819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615a559081620004948239608051816135fb015260a051818181610f57015261371c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126c15750806306fdde03146125fc578063081812fc146125de578063095ea7b31461244a5780631400ecec146123a557806316844456146120e15780631c1cdd4c1461207b5780631e99d5691461205d57806323b872dd1461203457806339a73c0314611ff157806340e58ee514611d9d578063425d30dd14611d7f57806342842e0e14611d2f57806342966c6814611b9f5780634857501f14611b295780634869e12d14611aed5780635fe3b56714611ac65780636352211e14611aa85780636d0cee7514611a5057806370a08231146119a657806375829def146119145780637cad6cd1146118425780637de6b1db146116325780638659c27014611339578063894e9a0d146110cc5780638bad38dd146110505780638f69b99314610fcd5780639067b67714610f7a5780639188ec8414610f3f57806395d89b4114610e2f578063a22cb46514610d5e578063a2ffb89714610c7c578063a6202bf214610b73578063a80fc07114610b1e578063ad35efd414610abb578063b256456914610a9d578063b637b86514610a3d578063b88d4fde146109b4578063b8a3be661461097d578063b971302a1461094e578063bc063e1a1461092b578063bc2be1be146108d8578063c156a11d14610820578063c33cd35e146106c1578063c87b56dd1461058e578063cc364f48146104f4578063d4dbd20b1461049f578063d511609f14610450578063d975dfed14610403578063e985e9c5146103ac578063ea5ead191461037e578063eac8f5b814610312578063f590c176146102ea578063f851a440146102c35763fdd46d601461027c57600080fd5b346102be5760603660031901126102be576102956127ee565b6044356001600160801b03811681036102be576102bc916102b46135f1565b600435613249565b005b600080fd5b346102be5760003660031901126102be5760206001600160a01b0360005416604051908152f35b346102be5760203660031901126102be576020610308600435612e24565b6040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102be5760403660031901126102be576102bc60043561039d6127ee565b6103a6826143c6565b91612e55565b346102be5760403660031901126102be576103c56127d8565b6103cd6127ee565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916143c6565b6001600160801b0360405191168152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602060026040600020015460801c604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102be5760203660031901126102be576004356000602060405161051881612928565b828152015280600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526040806000205464ffffffffff82519161055b83612928565b818160a01c16835260c81c16602082015261058c825180926020908164ffffffffff91828151168552015116910152565bf35b346102be576020806003193601126102be57600435906105cc6105c78360005260056020526001600160a01b0360406000205416151590565b612ba7565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106b55760009261063c575b506106386040519282849384528301906127b3565b0390f35b9091503d806000833e61064f8183612975565b81019082818303126102be5780519067ffffffffffffffff82116102be570181601f820112156102be57805161068481612997565b926106926040519485612975565b8184528482840101116102be576106ae91848085019101612790565b9082610623565b6040513d6000823e3d90fd5b346102be57600319602036820181136102be5760043567ffffffffffffffff928382116102be576101409082360301126102be576106fd6135f1565b6040519261070a8461290b565b61071682600401612804565b845261072460248301612a35565b6020850152610735604483016128e2565b6040850152610746606483016128e2565b91606092606086015261075b60848201612804565b608086015261076c60a482016129b3565b60a086015261077d60c48201612804565b60c086015261078f3660e48301612ad0565b60e08601526101248101359182116102be5701366023820112156102be576004810135926107bc84612a1d565b936107ca6040519586612975565b80855260246060602087019202840101923684116102be57602401905b838210610808576020610800888861010082015261366e565b604051908152f35b8285916108153685612a47565b8152019101906107e7565b346102be5760403660031901126102be5760043561083c6127ee565b906108456135f1565b80600052600b60205260ff60016040600020015460a81c1615610367578060005260056020526001600160a01b0360406000205416918233036108b5576102bc9261088f836143c6565b6001600160801b0381166108a4575b506140df565b6108af908285612e55565b8461089e565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102be5760003660031901126102be57602060405167016345785d8a00008152f35b346102be5760203660031901126102be57602061096c600435612ded565b6001600160a01b0360405191168152f35b346102be5760203660031901126102be57600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102be5760803660031901126102be576109cd6127d8565b6109d56127ee565b6064359167ffffffffffffffff83116102be57366023840112156102be57826004013591610a0283612997565b92610a106040519485612975565b80845236602482870101116102be5760208160009260246102bc9801838801378501015260443591612d57565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052610638610a896004604060002001612c90565b60405191829160208352602083019061287e565b346102be5760203660031901126102be576020610308600435612d20565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757610af590613f79565b6040516005821015610b08576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102be5760203660031901126102be57610b8c6127d8565b6001600160a01b038060005416338103610c5357508116908160005260026020526001600160801b0360406000205416908115610c225781610bf49184600052600260205260406000206fffffffffffffffffffffffffffffffff198154169055339061435e565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102be5760603660031901126102be5767ffffffffffffffff6004358181116102be57610cae90369060040161284d565b9190610cb86127ee565b916044359081116102be57610cd190369060040161284d565b92610cda6135f1565b838503610d275760005b858110610ced57005b80610d21610cfe6001938988612c17565b3584610d13610d0e858b8a612c17565b612abc565b91610d1c6135f1565b613249565b01610ce4565b60448585604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102be5760403660031901126102be57610d776127d8565b602435908115158092036102be576001600160a01b031690813314610deb57336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102be5760003660031901126102be5760405160006004549060018260011c9160018416918215610f35575b6020948585108414610f1f578587948686529182600014610eff575050600114610ea2575b50610e8e92500383612975565b6106386040519282849384528301906127b3565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610ee7575050610e8e935082010185610e81565b80548389018501528794508693909201918101610ed0565b60ff191685820152610e8e95151560051b8501019250879150610e819050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610e5c565b346102be5760003660031901126102be5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761100790613f79565b600581101580610b085760028214908115611043575b8115611031575b6020826040519015158152f35b9050610b085760046020911482611024565b505060038114600061101d565b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c53575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102be5760203660031901126102be5760606101406040516110ee81612958565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152611132612c3d565b6101208201520152600435600052600b60205260ff60016040600020015460a81c161561132157600435600052600b602052604060002061121560046040519261117b84612958565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015261120960028201612c5c565b61012085015201612c90565b610140820152611226600435613f79565b906005821015610b085760026101409214611315575b610638604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130161012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c083019061287e565b6000606082015261123c565b602460405162b8e7e760e51b81526004356004820152fd5b346102be576020806003193601126102be5760043567ffffffffffffffff81116102be5761136b90369060040161284d565b906113746135f1565b6000915b80831061138157005b61138c838284612c17565b35926113966135f1565b61139f84612b70565b156113bc5760248460405190634a5541ef60e01b82526004820152fd5b6113c884929394612e24565b61161a576113ec82600052600b6020526001600160a01b0360406000205416331490565b156108b5576113fa82613586565b82600052600b8087526114136002604060002001612c5c565b906001600160801b0392838351168482161015611602578560005281895260ff60406000205460f01c16156115ea579061148182858b6114777f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509683895116612a04565b9601511690612a04565b9580600052818a526040600020938a855498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617875560038882169788156115d0575b0197831697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a16958691600584528b604060002054169687945260019b8c60406000200154169461151d8b858861435e565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b61157d575b5050505050019190611378565b813b156102be5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16115c1575b80808080611570565b6115ca90612944565b856115b8565b60018101600160a01b60ff60a01b198254161790556114c9565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102be576020806003193601126102be57600435906116506135f1565b81600052600b815260ff60016040600020015460a81c161561182b5761167582613f79565b6005811015610b08576004810361169e5760248360405190634a5541ef60e01b82526004820152fd5b600381036116be576024836040519063fe19f19f60e01b82526004820152fd5b600214611813576116e582600052600b6020526001600160a01b0360406000205416331490565b156108b55781600052600b815260ff60406000205460f01c16156117fb5781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b61178c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102be57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af115611760576117f590612944565b83611760565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c535750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116118fe5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102be5760203660031901126102be5761192d6127d8565b6000546001600160a01b038082169233840361197f576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102be5760203660031901126102be576001600160a01b036119c76127d8565b1680156119e65760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57600435611a876105c78260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be57602061096c600435612bf2565b346102be5760003660031901126102be5760206001600160a01b0360015416604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916142e3565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576000611b6582613f79565b6005811015610b0857600203611b83575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611b76565b346102be5760203660031901126102be57600435611bbb6135f1565b611bc481612b70565b15611cfe57611bd28161427a565b15611cde57611be081612bf2565b611be982612d20565b159081611cd5575b81611cc2575b50611caa57602081611c297ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612bf2565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611bf7565b60009150611bf1565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102be57611d3d36612818565b60405191602083019383851067ffffffffffffffff861117611d69576102bc9460405260008452612d57565b634e487b7160e01b600052604160045260246000fd5b346102be5760203660031901126102be576020610308600435612b70565b346102be576020806003193601126102be5760043590611dbb6135f1565b611dc482612b70565b15611de15760248260405190634a5541ef60e01b82526004820152fd5b611dea82612e24565b61161a57611e0e82600052600b6020526001600160a01b0360406000205416331490565b156108b557611e1c82613586565b9180600052600b8252611e356002604060002001612c5c565b906001600160801b03938483511685821610156118135781600052600b845260ff60406000205460f01c16156117fb57808585611e78611e829483885116612a04565b9501511690612a04565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161787556003888616978815611fd7575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b87526001604060002001541694611f608d858861435e565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b611f9257005b813b156102be5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611fce57005b6102bc90612944565b60018101600160a01b60ff60a01b19825416179055611eeb565b346102be5760203660031901126102be576001600160a01b036120126127d8565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102be576102bc61204536612818565b916120586120538433614000565b612aff565b6140df565b346102be5760003660031901126102be576020600954604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576120b590613f79565b6005811015610b085780602091159081156120d6575b506040519015158152f35b6001915014826120cb565b346102be57602060031981813601126102be576004359067ffffffffffffffff908183116102be57610120833603918201126102be5761211f6135f1565b61010483013590602219018112156102be578201916004830135928284116102be57602481016060916060860280360383136102be5760249061216188612a1d565b9761216f604051998a612975565b8852888801920101913683116102be57905b8783831061238e5787878782519061219882612a1d565b916121a66040519384612975565b808352601f196121b582612a1d565b018660005b8281106123785750505064ffffffffff90814216946001600160801b0396876121e28261364d565b515116828a6121f08461364d565b51015116858060406122018661364d565b510151168a01169060405192612216846128ef565b83528b830152604082015261222a8761364d565b526122348661364d565b506001938660015b8a8c8783106122f757908b846001600160a01b038c60a4810135828116908190036102be57610800956122b7956122e79461227960248601612a9b565b61228560448701612a9b565b61229160648801612aa8565b9161229e88600401612aa8565b94846122ac60848b01612abc565b966040519d8e61290b565b168c528d8c0152151560408b0152151560608a01521660808801521660a086015260c085015260c4369101612ad0565b60e083015261010082015261366e565b88938580604061232b8b8661231b8a8e9a612312828d61365a565b5151169a61365a565b510151169460001989019061365a565b5101511681604061233c888c61365a565b5101511601169160405193612350856128ef565b84528301526040820152612364828b61365a565b5261236f818a61365a565b5001879061223c565b612380612c3d565b8282880101520187906121ba565b849161239a3685612a47565b815201910190612181565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675760209060009080600052600b8352604060002060ff815460f01c1680612438575b61240f575b50506001600160801b0360405191168152f35b61243192506001600160801b03600261242b9201541691613586565b90612a04565b82806123fc565b5060ff600182015460a01c16156123f7565b346102be5760403660031901126102be576124636127d8565b602435906001600160a01b03808061247a85612bf2565b169216918083146125745780331490811561254f575b50156124e5578260005260076020526040600020826001600160a01b03198254161790556124bd83612bf2565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff6040600020541684612490565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57602061096c6004356129c7565b346102be5760003660031901126102be5760405160006003549060018260011c91600184169182156126b7575b6020948585108414610f1f578587948686529182600014610eff57505060011461265a5750610e8e92500383612975565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b85831061269f575050610e8e935082010185610e81565b80548389018501528794508693909201918101612688565b92607f1692612629565b346102be5760203660031901126102be57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102be57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612766575b811561273c575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612735565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061272e565b60005b8381106127a35750506000910152565b8181015183820152602001612793565b906020916127cc81518092818552858086019101612790565b601f01601f1916010190565b600435906001600160a01b03821682036102be57565b602435906001600160a01b03821682036102be57565b35906001600160a01b03821682036102be57565b60609060031901126102be576001600160a01b039060043582811681036102be579160243590811681036102be579060443590565b9181601f840112156102be5782359167ffffffffffffffff83116102be576020808501948460051b0101116102be57565b90815180825260208080930193019160005b82811061289e575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612890565b359081151582036102be57565b6060810190811067ffffffffffffffff821117611d6957604052565b610120810190811067ffffffffffffffff821117611d6957604052565b6040810190811067ffffffffffffffff821117611d6957604052565b67ffffffffffffffff8111611d6957604052565b610160810190811067ffffffffffffffff821117611d6957604052565b90601f8019910116810190811067ffffffffffffffff821117611d6957604052565b67ffffffffffffffff8111611d6957601f01601f191660200190565b35906001600160801b03821682036102be57565b6129ea6105c78260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116118fe57565b67ffffffffffffffff8111611d695760051b60200190565b359064ffffffffff821682036102be57565b91908260609103126102be57604051612a5f816128ef565b8092612a6a816129b3565b825260208101359067ffffffffffffffff821682036102be576040612a96918193602086015201612a35565b910152565b3580151581036102be5790565b356001600160a01b03811681036102be5790565b356001600160801b03811681036102be5790565b91908260409103126102be57604051612ae881612928565b6020808294612af681612804565b84520135910152565b15612b0657565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460a01c1690565b15612bae57565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c14811515612ba7565b90565b9190811015612c275760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190612c4a826128ef565b60006040838281528260208201520152565b90604051612c69816128ef565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612c9c81612a1d565b92604093612cad6040519182612975565b82815280946020809201926000526020600020906000935b858510612cd457505050505050565b60018481928451612ce4816128ef565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cc5565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460b01c1690565b90612d7b939291612d6b6120538433614000565b612d768383836140df565b6149fa565b15612d8257565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260406000205460f81c90565b92919092612e616135f1565b600093612e6d82612b70565b61323157612e9182600052600b6020526001600160a01b0360406000205416331490565b90811593848095613221575b61320257838752602094600586526001600160a01b039060409482868b20541690806131f6575b6131d15782851680156131a8576001600160801b039081861691821561317857612f0a8a60028f8c908f600b90612efa866142e3565b9583525220015460801c90612a04565b8181168411613147575090897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c8f60018d8b928d9b9a9998612f9b612f69612f528a612ded565b9e8a8552600b89526002868620015460801c6143ee565b898452600b885260028585200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c5c565b90612fb6818884015116928286818351169201511690612a04565b161115613119575b868152600b85522001541694612fd5818d8861435e565b8c51908152a4803314158061310f575b6130a9575b508061309f575b613025575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b88929116803b1561309b578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613083575b808080612ff6565b61308d8691612944565b613097578461307b565b8480fd5b8280fd5b50803b1515612ff1565b8a813b1561310c578751636fd110e960e01b8152600481018a90523360248201526001600160a01b03881660448201526001600160801b0387166064820152918290608490829084905af115612fea57613105909a919a612944565b9838612fea565b80fd5b50803b1515612fe5565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612fbe565b895163287ecaef60e21b8152600481018c90526001600160801b038981166024830152919091166044820152606490fd5b60248a8a51907fd2aabcd90000000000000000000000000000000000000000000000000000000082526004820152fd5b600487517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b6064878487895192632dcbf6b960e11b84526004840152336024840152166044820152fd5b50808386161415612ec4565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b5061322b8461427a565b15612e9d565b60248260405190634a5541ef60e01b82526004820152fd5b9291909261325681612b70565b61356e5761327a81600052600b6020526001600160a01b0360406000205416331490565b801592838061355e575b61353f57600095838752602094600586526001600160a01b039060409482868b2054169080613533575b61350e5782841680156131a8576001600160801b0390818716918215613178576132d78a6143c6565b81811684116134dd575090897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c8f60018d8b928e9b9a999861331f612f69612f528a612ded565b9061333a818884015116928286818351169201511690612a04565b1611156134af575b868152600b85522001541694613359818c8861435e565b8c51908152a480331415806134a5575b613446575b508061343c575b6133a857505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b1690813b15613438578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613429575b85948180612ff6565b61343290612944565b38613420565b8780fd5b50803b1515613375565b8a813b1561310c578751636fd110e960e01b8152600481018a90523360248201526001600160a01b03871660448201526001600160801b0388166064820152918290608490829084905af11561336e5761349f90612944565b3861336e565b50803b1515613369565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613342565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b6064878486895192632dcbf6b960e11b84526004840152336024840152166044820152fd5b508083851614156132ae565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b506135688361427a565b15613284565b60249060405190634a5541ef60e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c1610156135e75760c81c1611156135d55760040154600110156135cc57612c14906144dd565b612c1490614409565b6001600160801b039150600201541690565b5050505050600090565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361362357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c275760200190565b8051821015612c275760209160051b010190565b906001600160a01b036001541660206001600160a01b0360c0850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106b557600090613f45575b6136ef91506001600160801b0360a08501511690602060e08601510151916146c8565b6001600160801b0381511661010084015164ffffffffff6020860151168215613f1b5781518015613ef1577f00000000000000000000000000000000000000000000000000000000000000008111613ec0575064ffffffffff60406137538461364d565b51015116811015613e695750600090819082815184905b808210613dd6575050505064ffffffffff421664ffffffffff8216811015613d965750506001600160801b0316808203613d5f5750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b0360c083015116600184015490750100000000000000000000000000000000000000000060408501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff000000000000000000000000000000000000000000006060890151151560b01b16921617171760018601556001600160a01b038451169161010085015192604061388585519560001987019061365a565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060208b015160a01b169660c81b169460f01b16911617171717845560005b818110613c8f575050600185016009556001600160a01b0360c08301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b0360c0840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036080830151168015613c4b576139cc6139c68760005260056020526001600160a01b0360406000205416151590565b15614807565b6139d586612d20565b1580613c42575b80613c3a575b613c225760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613a2d6139c68960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a1613abd6001600160a01b0360c0840151166001600160801b03808451168160208601511601169030903390614852565b6001600160801b0360408201511680613bf3575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb613bb06001600160a01b03845116926001600160a01b03608086015116946001600160a01b0360c08201511696613be8613bc860408401511515928c606086015115156001600160a01b0360e061010089015194549864ffffffffff6040519a613b5c8c612928565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e088015286019061287e565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613c1c906001600160a01b0360c0850151166001600160a01b0360e08601515116903390614852565b38613ad1565b60248660405190630da9b01360e01b82526004820152fd5b5060006139e2565b508015156139dc565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b613c9e8161010086015161365a565b519060048601549168010000000000000000831015611d695760018301806004890155831015612c275760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613921565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613dfa906001600160801b03613df1858861365a565b515116906143ee565b9364ffffffffff806040613e0e868561365a565b51015116941680851115613e2c57506001849301919291909261376a565b8385606492604051927f7b0bada8000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613e7a8461364d565b5101516040517fb4c9e52c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d602011613f71575b81613f5f60209383612975565b810103126102be576136ef90516136cc565b3d9150613f52565b80600052600b602052604060002060ff600182015460a01c16600014613fa0575050600490565b805460f81c613ff9575460a01c64ffffffffff164210613ff357613fc381613586565b90600052600b6020526001600160801b038060026040600020015416911610600014613fee57600190565b600290565b50600090565b5050600390565b906001600160a01b03808061401484612bf2565b16931691838314938415614047575b508315614031575b50505090565b61403d919293506129c7565b161438808061402b565b909350600052600860205260406000208260005260205260ff604060002054169238614023565b1561407557565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b9061410892916140ee83612bf2565b916001600160a01b0394859384809416968791161461406e565b16908115806142115761411a84612d20565b159081614208575b50806141ff575b6141e757918084926141697ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661416285612bf2565b161461406e565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515614129565b90501538614122565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b60009080825260056020526001600160a01b0380604084205416928333149384156142bf575b505082156142ad57505090565b9091506142ba33926129c7565b161490565b60ff92945090604091815260086020528181203382526020522054169138806142a0565b80600052600b6020526142fc6002604060002001612c5c565b81600052600b602052604060002060ff600182015460a01c1660001461432f57506001600160801b039150602001511690565b5460f81c6143415750612c1490613586565b612c1491506001600160801b036040818351169201511690612a04565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611d69576143c4926040526148bd565b565b612c14906143d3816142e3565b90600052600b60205260026040600020015460801c90612a04565b9190916001600160801b03808094169116019182116118fe57565b64ffffffffff61443e600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614b8d565b91808252600b602052600460408320018054156144c95790829167ffffffffffffffff935261449b6020832054828452600b6020526144966001600160801b03968760026040882001541696879360801c1690614c7d565b614ceb565b9283136144b15750506144ad90614dd5565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b60205260409081812082519361450485612958565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c16151561010088015261014061459f600461459060028801612c5c565b966101208b0197885201612c90565b97019187835280876145b1889a61364d565b5101511693828288965b16106146905750916146456144969284888161464a98976001600160801b039e8f6145e78b8a5161365a565b5151169d8a8f9b602061460467ffffffffffffffff928d5161365a565b5101511699848361461684845161365a565b5101511696508115614684576146349293505190600019019061365a565b5101511680925b0316920316614b8d565b614c7d565b92831361466357505061465d8391614dd5565b16011690565b51602001519293928316928416831015915061467f9050575090565b905090565b5050505116809261463b565b8094986001600160801b0390816146a88c885161365a565b51511601169801938282808a6146bf89895161365a565b510151166145bb565b9092916146d3612c3d565b936001600160801b03928381169182156147df5767016345785d8a00008082116147a857808511614771575061471d8561470e819386615901565b16946020890195865284615901565b1691846147346040890194808652828751166143ee565b16101561475b5761474d84918261475695511690612a04565b91511690612a04565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516147f2816128ef565b60008152600060208201526000604082015290565b1561480e57565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611d69576143c4926040525b6001600160a01b03169061491d6040516148d681612928565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16149176149ca565b916159b0565b8051918215918483156149a2575b5050509050156149385750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b9193818094500103126149c65782015190811515820361310c57508038808461492b565b5080fd5b3d156149f5573d906149db82612997565b916149e96040519384612975565b82523d6000602084013e565b606090565b9290803b15614b8457614a64916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906127b3565b03916000968791165af190829082614b23575b5050614afd57614a856149ca565b80519081614af85760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614b7c575b81614b4060209383612975565b810103126149c65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361310c5750903880614a77565b3d9150614b33565b50505050600190565b600160ff1b808214908115614c73575b50614c49576000811215614c4057614bc6816000035b6000841215614c39578360000390614e11565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614c025760001991181315614bfc5790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614e11565b614bc681614bb3565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614b9d565b80614c985750614c9357670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614ce5575080614cbd575050670de0b6b3a764000090565b670de0b6b3a76400008114614ce157614cdc90614496612c1493614f0b565b61504d565b5090565b91505090565b600160ff1b808214908115614dcb575b50614da1576000811215614d9857614d24816000035b6000841215614d91578360000390615901565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614d5a5760001991181315614bfc5790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615901565b614d2481614d11565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614cfb565b60008112614de05790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ecd5782851015614e9157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614edb570490565b634e487b7160e01b600052601260045260246000fd5b8015614edb576ec097ce7bc90715b34b9f10000000000590565b8060008083131561501c57670de0b6b3a764000092838112614ff957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614fed57506706f05b59d3b20000905b848213614fc15750505050500290565b808391020590671bc16d674ec80000821215614fe0575b831d90614fb1565b8091950194831d90614fd8565b93505093925050020290565b6000199392508015614edb576ec097ce7bc90715b34b9f10000000000591614f2c565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b600081121561507c5768033dd1780914b97114198112613ff3576150739060000361504d565b612c1490614ef1565b680a688906bd8affffff81136158d057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166157b3575b66ff00000000000083166156ab575b65ff000000000083166155ab575b64ff0000000083166154b3575b63ff00000083166153c3575b62ff000083166152db575b61ff0083166151fb575b60ff8316615124575b02911c60bf031c90565b608083166151e9575b8383166151d7575b602083166151c5575b601083166151b3575b600883166151a1575b6004831661518f575b6002831661517d575b600183161561511a576801000000000000000102831c61511a565b6801000000000000000102831c615162565b6801000000000000000302831c615159565b6801000000000000000602831c615150565b6801000000000000000b02831c615147565b6801000000000000001602831c61513e565b6801000000000000002c02831c615135565b6801000000000000005902831c61512d565b61800083166152c9575b61400083166152b7575b61200083166152a5575b6110008316615293575b6108008316615281575b610400831661526f575b610200831661525d575b61010083161561511157680100000000000000b102831c615111565b6801000000000000016302831c615241565b680100000000000002c602831c615237565b6801000000000000058c02831c61522d565b68010000000000000b1702831c615223565b6801000000000000162e02831c615219565b68010000000000002c5d02831c61520f565b680100000000000058b902831c615205565b6280000083166153b1575b62400000831661539f575b62200000831661538d575b62100000831661537b575b620800008316615369575b620400008316615357575b620200008316615345575b62010000831615615107576801000000000000b17202831c615107565b680100000000000162e402831c615328565b6801000000000002c5c802831c61531d565b68010000000000058b9102831c615312565b680100000000000b172102831c615307565b68010000000000162e4302831c6152fc565b680100000000002c5c8602831c6152f1565b6801000000000058b90c02831c6152e6565b638000000083166154a1575b6340000000831661548f575b6320000000831661547d575b6310000000831661546b575b63080000008316615459575b63040000008316615447575b63020000008316615435575b63010000008316156150fc5768010000000000b1721802831c6150fc565b6801000000000162e43002831c615417565b68010000000002c5c86002831c61540b565b680100000000058b90c002831c6153ff565b6801000000000b17217f02831c6153f3565b680100000000162e42ff02831c6153e7565b6801000000002c5c85fe02831c6153db565b68010000000058b90bfc02831c6153cf565b6480000000008316615599575b6440000000008316615587575b6420000000008316615575575b6410000000008316615563575b6408000000008316615551575b640400000000831661553f575b640200000000831661552d575b6401000000008316156150f057680100000000b17217f802831c6150f0565b68010000000162e42ff102831c61550e565b680100000002c5c85fe302831c615501565b6801000000058b90bfce02831c6154f4565b68010000000b17217fbb02831c6154e7565b6801000000162e42fff002831c6154da565b68010000002c5c8601cc02831c6154cd565b680100000058b90c0b4902831c6154c0565b658000000000008316615699575b654000000000008316615687575b652000000000008316615675575b651000000000008316615663575b650800000000008316615651575b65040000000000831661563f575b65020000000000831661562d575b650100000000008316156150e3576801000000b17218355102831c6150e3565b680100000162e430e5a202831c61560d565b6801000002c5c863b73f02831c6155ff565b68010000058b90cf1e6e02831c6155f1565b680100000b1721bcfc9a02831c6155e3565b68010000162e43f4f83102831c6155d5565b680100002c5c89d5ec6d02831c6155c7565b6801000058b91b5bc9ae02831c6155b9565b668000000000000083166157a1575b6640000000000000831661578f575b6620000000000000831661577d575b6610000000000000831661576b575b66080000000000008316615759575b66040000000000008316615747575b66020000000000008316615735575b66010000000000008316156150d55768010000b17255775c0402831c6150d5565b6801000162e525ee054702831c615714565b68010002c5cc37da949202831c615705565b680100058ba01fb9f96d02831c6156f6565b6801000b175effdc76ba02831c6156e7565b680100162f3904051fa102831c6156d8565b6801002c605e2e8cec5002831c6156c9565b68010058c86da1c09ea202831c6156ba565b67800000000000000083166158b1575b674000000000000000831661589f575b672000000000000000831661588d575b671000000000000000831661587b575b6708000000000000008316615869575b6704000000000000008316615857575b6702000000000000008316615845575b6701000000000000008316156150c657680100b1afa5abcbed6102831c6150c6565b68010163da9fb33356d802831c615823565b680102c9a3e778060ee702831c615813565b6801059b0d31585743ae02831c615803565b68010b5586cf9890f62a02831c6157f3565b6801172b83c7d517adce02831c6157e3565b6801306fe0a31b7152df02831c6157d3565b5077b504f333f9de6484800000000000000000000000000000006157c3565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461599f57670de0b6b3a7640000908183101561596857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b91929015615a1157508151156159c4575090565b3b156159cd5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015615a245750805190602001fd5b6108d49060405191829162461bcd60e51b83526020600484015260248301906127b356fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003e757601f196001600160401b03601f62004c533881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516148309081620004238239608051816137190152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612dd85750806306fdde0314612d14578063081812fc14612cf5578063095ea7b314612b665780631400ecec14612ac65780631c1cdd4c14612a615780631e99d56914612a4357806323b872dd14612a1957806339a73c03146129d857806340e58ee51461273a578063425d30dd1461271b57806342842e0e146126cb57806342966c68146125415780634857501f146124b75780634869e12d1461247c5780635fe3b567146124555780636352211e146124255780636d0cee75146123cf57806370a082311461232657806375829def14612293578063780a82c8146122435780637cad6cd1146121725780637de6b1db14611f925780638659c27014611c71578063894e9a0d14611a1d5780638bad38dd146119a05780638f69b993146119045780639067b677146118b157806395d89b41146117a257806396ce143114611683578063a22cb465146115b2578063a2ffb897146111c5578063a6202bf2146110c8578063a80fc07114611076578063ab167ccc14610f3d578063ad35efd414610edb578063b256456914610ebc578063b88d4fde14610e32578063b8a3be6614610dfd578063b971302a14610dae578063bc063e1a14610d8b578063bc2be1be14610d3b578063c156a11d146109c1578063c87b56dd14610887578063cc364f48146107d9578063d4dbd20b14610787578063d511609f1461073b578063d975dfed146106ef578063e985e9c51461069a578063ea5ead1914610674578063eac8f5b81461060b578063f590c176146105e2578063f851a440146105bc5763fdd46d601461027357600080fd5b346105b95760603660031901126105b95760043561028f612f07565b610297613047565b906102a061370f565b6102a98361313a565b6105a1576102cd83600052600b6020526001600160a01b0360406000205416331490565b90811580610591575b61057257838552602092600584526001600160a01b0391826040882054169380610566575b61054057828116928315610516576001600160801b038084169384156104fe57610324896140f8565b82811686116104ca5750938093926103ca9261038f6103578d9a99988d8c52600b8d52600260408d20015460801c614120565b8c8b52600b8c5261038a600260408d20019182906001600160801b036001600160801b031983549260801b169116179055565b613226565b906103ab818c840151169282604081835116920151169061309a565b16111561049a575b898852600b89526001604089200154169283614090565b82877f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d88604051868152a48233141580610490575b610432575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b1561048c57608484928360405195869485936313375c3b60e01b85528b6004860152336024860152604485015260648401525af1610474575b8080610404565b61047d90612f83565b61048857823861046d565b8280fd5b8380fd5b50823b15156103ff565b898852600b89526040882060018101600160c81b60ff60c81b1982541617905560ff60f01b1981541690556103b3565b60405163287ecaef60e21b8152600481018b90526001600160801b03928316602482015291166044820152606490fd5b0390fd5b6024896040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b858360649260405192632dcbf6b960e11b84526004840152336024840152166044820152fd5b508383821614156102fb565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b5061059b8461376b565b156102d6565b60248360405190634a5541ef60e01b82526004820152fd5b80fd5b50346105b957806003193601126105b9576001600160a01b036020915416604051908152f35b50346105b95760203660031901126105b9576020610601600435613327565b6040519015158152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760016040836001600160a01b039360209552600b855220015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b50346105b95760403660031901126105b957600435610691612f07565b610297826140f8565b50346105b95760403660031901126105b9576106b4612ef1565b60406106be612f07565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346105b95760203660031901126105b95760ff6001604060043593848152600b60205220015460d01c161561065d5761072a6020916140f8565b6001600160801b0360405191168152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760408260029260209452600b845220015460801c604051908152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760036040836001600160801b039360209552600b855220015416604051908152f35b50346105b95760203660031901126105b9576004356107f6613207565b50808252600b60205260ff600160408420015460d01c161561065d578160409160609352600b60205220600181549164ffffffffff918291015460a01c16906040519261084284612fd1565b818160a01c16845260c81c166020830152604082015261088560405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b50346105b9576020806003193601126109b1576004356108c56108c08260005260056020526001600160a01b0360406000205416151590565b613171565b826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9283156109b5578093610934575b5050610930604051928284938452830190612ecc565b0390f35b909192503d8082843e6109478184613009565b82019183818403126109b15780519067ffffffffffffffff8211610488570182601f820112156109b15780519161097d8361302b565b9361098b6040519586613009565b8385528584840101116105b95750906109a991848085019101612ea9565b90388061091a565b5080fd5b604051903d90823e3d90fd5b50346105b95760403660031901126105b9576004356109de612f07565b906109e761370f565b808352602091600b835260ff600160408620015460d01c1615610d2457818452600583526001600160a01b03806040862054169081330361057257610a2b846140f8565b906001600160801b0390818316918215938415610a52575b89610a4f898989613574565b80f35b610a5a61370f565b610a638861313a565b610d0c57610a8788600052600b6020526001600160a01b0360406000205416331490565b94851580610cfc575b610cdd57888b5260058a528360408c2054169580610cd3575b610caf57861561051657610c9757610ac0886140f8565b8281168511610c67575090610b20610aed8b969594938a8852600b8c52600260408920015460801c614120565b898752600b8b5261038a600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b90610b3c818b840151169282604081835116920151169061309a565b161115610c37575b868452600b8852600160408520015416610b5f828683614090565b84877f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8a604051868152a48133141580610c2d575b610bd2575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7610a4f94604051858152a13880808080610a43565b813b156104885782916084839260405194859384926313375c3b60e01b84528b600485015233602485015289604485015260648401525af1610c15575b80610b99565b610c1e90612f83565b610c29578438610c0f565b8480fd5b50813b1515610b94565b868452600b88526040842060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055610b44565b60405163287ecaef60e21b8152600481018a90526001600160801b03928316602482015291166044820152606490fd5b6024886040519063d2aabcd960e01b82526004820152fd5b6064898860405191632dcbf6b960e11b835260048301523360248301526044820152fd5b5085871415610aa9565b60405163216caf0d60e01b8152600481018a9052336024820152604490fd5b50610d068961376b565b15610a90565b60248860405190634a5541ef60e01b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b50346105b957806003193601126105b957602060405167016345785d8a00008152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d576040826001600160a01b039260209452600b8452205416604051908152f35b50346105b95760203660031901126105b95760ff600160406020936004358152600b855220015460d01c166040519015158152f35b50346105b95760803660031901126105b957610e4c612ef1565b610e54612f07565b906064359067ffffffffffffffff821161048c573660238301121561048c5781600401359284610e838561302b565b93610e916040519586613009565b85855236602487830101116109b15785610a4f96602460209301838801378501015260443591613291565b50346105b95760203660031901126105b957602061060160043561325a565b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d57610f149061340e565b604051906005811015610f2957602092508152f35b602483634e487b7160e01b81526021600452fd5b50346105b9576101403660031901126105b957610f5861370f565b610f60613207565b9064ffffffffff80421680845260c43582811681036110715781018216602085015260e4359081831682036110715701166040830152606435916001600160a01b03918284168094036105b957506084358015158091036110715760a435908115158092036110715760243594848616809603611071576004359585871680970361107157604435906001600160801b038216809203611071576040519761100789612fb4565b8852602088015260408701526060860152608085015260a084015260c0830152604061010319360112611071576040519161104183612fed565b61010435918216820361107157826110699260209452610124358482015260e082015261384f565b604051908152f35b600080fd5b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760026040836001600160801b039360209552600b855220015416604051908152f35b50346105b95760203660031901126105b9576110e2612ef1565b6001600160a01b038083541633810361119c575081169081835260026020526001600160801b0360408420541690811561116b578161113c918486526002602052604086206001600160801b031981541690553390614090565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346105b95760603660031901126105b95767ffffffffffffffff600435818111610488576111f8903690600401612f52565b90611201612f07565b92604435908111610c295761121a903690600401612f52565b61122594919461370f565b80840361157b5791926001600160a01b038216159290865b818110611248578780f35b6112538183886131e1565b359061126081858a6131e1565b356001600160801b03811681036110715761127961370f565b6112828361313a565b6105a1576112a683600052600b6020526001600160a01b0360406000205416331490565b80158061156b575b61057257838b5260056020526001600160a01b0360408c2054169080611558575b61152b5787610516576001600160801b03821615611513576112f0846140f8565b6001600160801b0381166001600160801b038416116114e15750908a91848352600b80602052611360600261038a611331868360408a20015460801c614120565b918988528460205260408820019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b03611384816020840151169282604081835116920151169061309a565b1611156114b1575b8584526020526001600160a01b036001604085200154166113b76001600160801b0384168a83614090565b6040516001600160801b0384168152867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b038d1693a480331415806114a7575b61143b575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161123d565b803b15610488576001600160a01b036084898580946001600160801b0360405197889687956313375c3b60e01b87528d60048801523360248801521660448601521660648401525af161148f575b80611405565b61149890612f83565b6114a3578838611489565b8880fd5b50803b1515611400565b858452806020526040842060018101600160c81b60ff60c81b1982541617905560ff60f01b19815416905561138c565b60405163287ecaef60e21b8152600481018690526001600160801b038481166024830152919091166044820152606490fd5b6024846040519063d2aabcd960e01b82526004820152fd5b6064846001600160a01b038960405192632dcbf6b960e11b84526004840152336024840152166044820152fd5b50806001600160a01b03881614156112cf565b506115758461376b565b156112ae565b83604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346105b95760403660031901126105b9576115cc612ef1565b60243590811515809203611071576001600160a01b03169081331461163f5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b50346105b9576101603660031901126105b95761169e61370f565b604051906116ab82612fb4565b6116b3612ef1565b82526116bd612f07565b60208301526116ca613047565b60408301526001600160a01b03906064358281168103611071576060840152608435801515810361107157608084015260a43580151581036110715760a084015260603660c31901126105b9575060405161172481612fd1565b64ffffffffff60c435818116810361107157825260e435818116810361107157602083015261010435908116810361107157604082015260c0830152604061012319360112611071576040519161177a83612fed565b61012435918216820361107157826110699260209452610144358482015260e082015261384f565b50346105b957806003193601126105b95760405190806004549160018360011c92600185169485156118a7575b602095868610811461189357858852879493929187908215611871575050600114611817575b505061180392500383613009565b610930604051928284938452830190612ecc565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b858310611859575050611803935082010138806117f5565b80548389018501528794508693909201918101611841565b925093505061180394915060ff191682840152151560051b82010138806117f5565b602483634e487b7160e01b81526022600452fd5b93607f16936117cf565b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d57600160408364ffffffffff9360209552600b855220015460a01c16604051908152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5761193d9061340e565b906005821015908161197e5760028314918215611992575b8215611969575b6020836040519015158152f35b90915061197e5750600460209114388061195c565b80634e487b7160e01b602492526021600452fd5b506003831491506000611955565b50346105b95760203660031901126105b9576004356001600160a01b0390818116809103610488578183541633810361119c575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b50346105b95760203660031901126105b957604051611a3b81612f97565b8181528160208201528160408201528160608201528160808201528160a08201528160c08201528160e08201528161010082015281610120820152610140611a81613207565b9101526004358152600b60205260ff600160408320015460d01c1615611c59576004358152600b60205260408120611b5a600260405192611ac184612f97565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a087015264ffffffffff8160a01c1660c0870152818160c81c16151560e0870152818160d01c16151561010087015260d81c16151561012085015201613226565b610140820152611b6b60043561340e565b6005811015610f29579160026101a09314611c4e575b50610885610140604051926001600160a01b03815116845264ffffffffff602082015116602085015264ffffffffff60408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a085015264ffffffffff60c08201511660c085015260e0810151151560e0850152610100810151151561010085015261012081015115156101208501520151610140830190604090816001600160801b0391828151168552826020820151166020860152015116910152565b606082015238611b81565b602460405162b8e7e760e51b81526004356004820152fd5b50346105b957602090816003193601126105b95760043567ffffffffffffffff81116109b157611ca683913690600401612f52565b9190611cb061370f565b83925b808410611cbe578480f35b611ccd848284979596976131e1565b3594611cd761370f565b611ce08661313a565b15611cfd5760248660405190634a5541ef60e01b82526004820152fd5b611d0686613327565b611f7a57611d2a86600052600b6020526001600160a01b0360406000205416331490565b15611f5b57611d3886613358565b95808552600b90818752611d5160026040882001613226565b906001600160801b039283835116848b161015611f435781885280895260ff604089205460f01c1615611f2b57611da18a858b611d9760409a9b9c9d9e8389511661309a565b960151169061309a565b92828a52818b52868a20908b8b7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50845497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a1617865560038a8216968715611f11575b01998516998a6001600160801b03198254161790556001600160a01b0380991698899360058652818e822054169889965260019d8e912001541694611e4e8b8588614090565b604080518a81526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78b604051858152a1813b611eb2575b505050505001919093919293611cb3565b813b15611f0d57899493919285809460849360405197889687956372eba20360e01b875260048701526024860152604485015260648401525af1611ef9575b808080611ea1565b611f0290612f83565b610c29578487611ef1565b8980fd5b60018101600160c81b60ff60c81b19825416179055611e08565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b6024866040519063fe19f19f60e01b82526004820152fd5b50346105b9576020806003193601126109b15760043590611fb161370f565b818352600b815260ff600160408520015460d01c1615610d2457611fd48261340e565b600581101561215e5760048103611ffd5760248360405190634a5541ef60e01b82526004820152fd5b6003810361201d576024836040519063fe19f19f60e01b82526004820152fd5b600214611f435761204482600052600b6020526001600160a01b0360406000205416331490565b1561213f57818352600b815260ff604084205460f01c1615611f2b57818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b6120e7575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561048857816024818580947f341a0bd90000000000000000000000000000000000000000000000000000000083528960048401525af161212b575b806120b8565b61213490612f83565b610488578238612125565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602484634e487b7160e01b81526021600452fd5b50346105b95760203660031901126105b9576004356001600160a01b0390818116809103610488578183541633810361119c5750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600954600019810190811161222f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b50346105b95760203660031901126105b9576122ad612ef1565b9080546001600160a01b03808216933385036122ff576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b50346105b95760203660031901126105b9576001600160a01b03612348612ef1565b168015612365578160409160209352600683522054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b50346105b95760203660031901126105b9576001600160a01b0360406020926004356124146108c08260005260056020526001600160a01b0360406000205416151590565b815260058452205416604051908152f35b50346105b95760203660031901126105b95760206124446004356131bc565b6001600160a01b0360405191168152f35b50346105b957806003193601126105b95760206001600160a01b0360015416604051908152f35b50346105b95760203660031901126105b95760ff6001604060043593848152600b60205220015460d01c161561065d5761072a6020916137d4565b50346105b95760203660031901126105b95760043590818152600b60205260ff600160408320015460d01c1615610d2457806124f28361340e565b92600584101561252d57600260209403612513575b50506040519015158152f35b8152600b8352604090205460f01c60ff1690503880612507565b602482634e487b7160e01b81526021600452fd5b50346105b95760203660031901126105b95760043561255e61370f565b6125678161313a565b1561269a576125758161376b565b1561267a57612583816131bc565b61258c8261325a565b159081612672575b8161265f575b50612647576020816125cc7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7936131bc565b90808552600783526001600160a01b0360408620926001600160a01b03199384815416905516918286526006845260408620600019815401905581865260058452604086209081541690558085604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a180f35b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b0391501615153861259a565b839150612594565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b50346105b9576126da36612f1d565b60405191602083019383851067ffffffffffffffff86111761270557610a4f94604052858452613291565b634e487b7160e01b600052604160045260246000fd5b50346105b95760203660031901126105b957602061060160043561313a565b50346105b9576020806003193601126109b1576004359061275961370f565b6127628261313a565b1561277f5760248260405190634a5541ef60e01b82526004820152fd5b9061278981613327565b6129c0576127ad81600052600b6020526001600160a01b0360406000205416331490565b1561267a576127bb81613358565b818452600b83526127d160026040862001613226565b926001600160801b03918285511683821610156129a857838652600b825260ff604087205460f01c16156129905792827ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce783612846878460409761283c8d9b6128f19b8e511661309a565b9b0151169061309a565b92848852600b825287868120947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84161788556003858216988915612976575b01948d169c858e6001600160801b0319819854161790556001600160a01b038094169b8c94600589526001818e892054169d8e98600b8c5220015416968588614090565b604080518b81526001600160801b0392831660208201529290911690820152606090a4604051848152a1823b612925578480f35b823b15610c2957608492859160405197889687956372eba20360e01b875260048701526024860152604485015260648401525af1612967575b81818080808480f35b61297090612f83565b3861295e565b60018101600160c81b60ff60c81b198254161790556128ad565b602484604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b6024906040519063fe19f19f60e01b82526004820152fd5b50346105b95760203660031901126105b9576001600160801b0360406020926001600160a01b03612a07612ef1565b16815260028452205416604051908152f35b50346105b957610a4f612a2b36612f1d565b91612a3e612a398433613495565b6130c9565b613574565b50346105b957806003193601126105b9576020600954604051908152f35b50346105b95760203660031901126105b957600435808252600b60205260ff600160408420015460d01c161561065d57612a9a9061340e565b90600582101561197e5760208215838115612abb575b506040519015158152f35b600191501482612ab0565b50346105b95760203660031901126105b95760043590818152600b60205260ff600160408320015460d01c1615610d2457602091604082828152600b85522060ff815460f01c1680612b54575b612b2b575b50506001600160801b0360405191168152f35b612b4d92506001600160801b036002612b479201541691613358565b9061309a565b3880612b18565b5060ff600182015460c81c1615612b13565b50346105b95760403660031901126105b957612b80612ef1565b602435906001600160a01b038080612b97856131bc565b16921691808314612c8b57803314908115612c6a575b5015612c0057828452600760205260408420826001600160a01b0319825416179055612bd8836131bc565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050845260086020526040842033855260205260ff60408520541638612bad565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b50346105b95760203660031901126105b957602061244460043561305d565b50346105b957806003193601126105b95760405190806003549160018360011c9260018516948515612dce575b602095868610811461189357858852879493929187908215611871575050600114612d7457505061180392500383613009565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b858310612db6575050611803935082010138806117f5565b80548389018501528794508693909201918101612d9e565b93607f1693612d41565b9050346109b15760203660031901126109b1576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361048857602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115612e7f575b8115612e55575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612e4e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612e47565b60005b838110612ebc5750506000910152565b8181015183820152602001612eac565b90602091612ee581518092818552858086019101612ea9565b601f01601f1916010190565b600435906001600160a01b038216820361107157565b602435906001600160a01b038216820361107157565b6060906003190112611071576001600160a01b0390600435828116810361107157916024359081168103611071579060443590565b9181601f840112156110715782359167ffffffffffffffff8311611071576020808501948460051b01011161107157565b67ffffffffffffffff811161270557604052565b610160810190811067ffffffffffffffff82111761270557604052565b610100810190811067ffffffffffffffff82111761270557604052565b6060810190811067ffffffffffffffff82111761270557604052565b6040810190811067ffffffffffffffff82111761270557604052565b90601f8019910116810190811067ffffffffffffffff82111761270557604052565b67ffffffffffffffff811161270557601f01601f191660200190565b604435906001600160801b038216820361107157565b6130806108c08260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116130b357565b634e487b7160e01b600052601160045260246000fd5b156130d057565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460d01c161561065d57600052600b60205260ff60016040600020015460c81c1690565b1561317857565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b03604060002054166131de811515613171565b90565b91908110156131f15760051b0190565b634e487b7160e01b600052603260045260246000fd5b6040519061321482612fd1565b60006040838281528260208201520152565b9060405161323381612fd1565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b80600052600b60205260ff60016040600020015460d01c161561065d57600052600b60205260ff60016040600020015460d81c1690565b906132b59392916132a5612a398433613495565b6132b0838383613574565b614469565b156132bc57565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460d01c161561065d57600052600b60205260406000205460f81c90565b600090808252600b6020526040822091825464ffffffffff42818360c81c16116134065780600186015460a01c1691824210156133f0576133a59394955060a01c168091039042036145fc565b90828152600b6020526001600160801b03926133cb8460026040852001541680946146dc565b9283116133d85750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b505091505090565b80600052600b602052604060002060ff600182015460c81c16600014613435575050600490565b805460f81c61348e575460a01c64ffffffffff1642106134885761345881613358565b90600052600b6020526001600160801b03806002604060002001541691161060001461348357600190565b600290565b50600090565b5050600390565b906001600160a01b0380806134a9846131bc565b169316918383149384156134dc575b5083156134c6575b50505090565b6134d29192935061305d565b16143880806134c0565b909350600052600860205260406000208260005260205260ff6040600020541692386134b8565b1561350a57565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b9061359d9291613583836131bc565b916001600160a01b03948593848094169687911614613503565b16908115806136a6576135af8461325a565b15908161369d575b5080613694575b61367c57918084926135fe7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7966020966135f7856131bc565b1614613503565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b508315156135be565b905015386135b7565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361374157565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b0380604084205416928333149384156137b0575b5050821561379e57505090565b9091506137ab339261305d565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613791565b80600052600b6020526137ed6002604060002001613226565b81600052600b602052604060002060ff600182015460c81c1660001461382057506001600160801b039150602001511690565b5460f81c61383257506131de90613358565b6131de91506001600160801b03604081835116920151169061309a565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa801561408457600090614050575b6138d091506001600160801b0360408501511690602060e086015101519161413b565b916001600160801b0383511660c082015190156140265764ffffffffff815116602082019064ffffffffff82511690818111613fe657505064ffffffffff604091511691019064ffffffffff8251169081811015613fa657505064ffffffffff8042169151169081811015613f66575050600954926001600160801b038151166040519061395d82612fd1565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff6020840151169064ffffffffff604085015116906080870151151560a088015115159364ffffffffff6001600160a01b038a5116975116604051976139cc89612f97565b88526020880152604087015260608601526000608086015260a085015260c0840152600060e0840152600161010084015261012083015261014082015284600052600b60205260406000206001600160a01b038251166001600160a01b0319825416178155613a6364ffffffffff602084015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b604082015181547eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b169078ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006080880151151560f81b169460c81b1691161717178155600181016001600160a01b0360a0840151166001600160a01b0319825416178155613b5a64ffffffffff60c085015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b60e083015181546101008501516101208601517fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921692151560c81b79ff00000000000000000000000000000000000000000000000000169290921791151560d01b7aff0000000000000000000000000000000000000000000000000000169190911790151560d81b7bff00000000000000000000000000000000000000000000000000000016179055610140909101518051602082015160801b6001600160801b03199081166001600160801b03928316176002850155926040906003019201511682825416179055600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b036020830151168015613f2257613cd5613ccf8660005260056020526001600160a01b0360406000205416151590565b1561427a565b613cde8561325a565b1580613f19575b80613f11575b613ef95760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613d36613ccf8860005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905586600052600582526040600020816001600160a01b0319825416179055866040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4868152a1613dc66001600160a01b036060840151166001600160801b038084511681602086015116011690309033906142c5565b6001600160801b0360408201511680613eca575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b0360208701511694613ec16001600160a01b03606089015116976080810151151560a0820151151590613e8b6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b613ef3906001600160a01b036060850151166001600160a01b0360e086015151169033906142c5565b38613dda565b60248560405190630da9b01360e01b82526004820152fd5b506000613ceb565b50801515613ce5565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f4c23297000000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161407c575b8161406a60209383613009565b81010312611071576138d090516138ad565b3d915061405d565b6040513d6000823e3d90fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117612705576140f692604052614330565b565b6131de90614105816137d4565b90600052600b60205260026040600020015460801c9061309a565b9190916001600160801b03808094169116019182116130b357565b909291614146613207565b936001600160801b03928381169182156142525767016345785d8a000080821161421b578085116141e45750614190856141818193866146dc565b169460208901958652846146dc565b1691846141a7604089019480865282875116614120565b1610156141ce576141c08491826141c99551169061309a565b9151169061309a565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050505050905060405161426581612fd1565b60008152600060208201526000604082015290565b1561428157565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612705576140f6926040525b6001600160a01b03169061439060405161434981612fed565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af161438a614439565b9161478b565b805191821591848315614415575b5050509050156143ab5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b9193818094500103126109b1578201519081151582036105b957508038808461439e565b3d15614464573d9061444a8261302b565b916144586040519384613009565b82523d6000602084013e565b606090565b9290803b156145f3576144d3916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c86523360048701521660248501526044840152608060648401526084830190612ecc565b03916000968791165af190829082614592575b505061456c576144f4614439565b805190816145675760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d6020116145eb575b816145af60209383613009565b810103126109b15751907fffffffff00000000000000000000000000000000000000000000000000000000821682036105b957509038806144e6565b3d91506145a2565b50505050600190565b670de0b6b3a76400009160001983830992808302928380861095039480860395146146b8578285101561467c57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156146c6570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461477a57670de0b6b3a7640000908183101561474357947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b919290156147ec575081511561479f575090565b3b156147a85790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156147ff5750805190602001fd5b6104fa9060405191829162461bcd60e51b8352602060048401526024830190612ecc56fea164736f6c6343000817000a"; + hex"60a034620003e757601f196001600160401b03601f62004e763881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a55600955604051614a5390816200042382396080518161393c0152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612fc45750806306fdde0314612f00578063081812fc14612ee1578063095ea7b314612d525780631400ecec14612cb25780631c1cdd4c14612c4d5780631e99d56914612c2f57806323b872dd14612c0557806339a73c0314612bc457806340e58ee514612926578063425d30dd1461290757806342842e0e146128b757806342966c681461272d5780634857501f146126a35780634869e12d146126685780635fe3b567146126415780636352211e146126225780636d0cee75146125cc57806370a082311461252357806375829def14612490578063780a82c8146124405780637cad6cd11461236f5780637de6b1db1461218f5780638659c27014611e6e578063894e9a0d14611c1a5780638bad38dd14611b9d5780638f69b99314611b015780639067b67714611aae57806395d89b411461199f57806396ce143114611880578063a22cb465146117af578063a2ffb89714611325578063a6202bf214611228578063a80fc071146111d6578063ab167ccc1461109d578063ad35efd41461103b578063b25645691461101c578063b88d4fde14610f92578063b8a3be6614610f5d578063b971302a14610f2d578063bc063e1a14610f0a578063bc2be1be14610eba578063c156a11d14610a74578063c87b56dd1461093a578063cc364f481461088c578063d4dbd20b1461083a578063d511609f146107ee578063d975dfed146107a2578063e985e9c51461074d578063ea5ead1914610727578063eac8f5b8146106be578063f590c17614610695578063f851a4401461066f5763fdd46d601461027357600080fd5b3461066c57606036600319011261066c5760043561028f6130f3565b610297613233565b61029f613932565b6102a883613326565b610654576102cc83600052600b6020526001600160a01b0360406000205416331490565b801592908380610644575b61062557848652602093600585526001600160a01b0391826040892054169080610619575b6105f35782841680156105c9576001600160801b03908187169182156105b1576103258a61431b565b818116841161057b5750918796959492918a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b888f9c989660408e6001926103c161038a6103738a613513565b9e8a8552600b89526002868620015460801c614343565b898452600b88526103bc6002868620019182906001600160801b036001600160801b031983549260801b169116179055565b613412565b906103dc818884015116928286818351169201511690613286565b16111561054d575b868152600b855220015416946103fb818c886142b3565b604051908152a48033141580610543575b6104ce575b50806104c4575b61044b575b847ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78789604051908152a180f35b1691823b156104c057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104a8575b80808061041d565b6104b19061316f565b6104bc5782386104a0565b8280fd5b8380fd5b50803b1515610418565b803b1561053f57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03861660448201526001600160801b0387166064820152879182908290608490829084905af1610527575b50610411565b6105309061316f565b61053b578538610521565b8580fd5b8680fd5b50803b151561040c565b868152600b8552818120838101600160c81b60ff60c81b1982541617905560ff60f01b1981541690556103e4565b60405163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b0390fd5b60248a6040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b606487848660405192632dcbf6b960e11b84526004840152336024840152166044820152fd5b508083851614156102fc565b60405163216caf0d60e01b815260048101869052336024820152604490fd5b5061064e8561398e565b156102d7565b60248360405190634a5541ef60e01b82526004820152fd5b80fd5b503461066c578060031936011261066c576001600160a01b036020915416604051908152f35b503461066c57602036600319011261066c5760206106b460043561354a565b6040519015158152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760016040836001600160a01b039360209552600b855220015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066c57604036600319011261066c576004356107446130f3565b6102978261431b565b503461066c57604036600319011261066c576107676130dd565b60406107716130f3565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b503461066c57602036600319011261066c5760ff6001604060043593848152600b60205220015460d01c1615610710576107dd60209161431b565b6001600160801b0360405191168152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408260029260209452600b845220015460801c604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760036040836001600160801b039360209552600b855220015416604051908152f35b503461066c57602036600319011261066c576004356108a96133f3565b50808252600b60205260ff600160408420015460d01c1615610710578160409160609352600b60205220600181549164ffffffffff918291015460a01c1690604051926108f5846131bd565b818160a01c16845260c81c166020830152604082015261093860405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b503461066c57602080600319360112610a64576004356109786109738260005260056020526001600160a01b0360406000205416151590565b61335d565b826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a685780936109e7575b50506109e36040519282849384528301906130b8565b0390f35b909192503d8082843e6109fa81846131f5565b8201918381840312610a645780519067ffffffffffffffff82116104bc570182601f82011215610a6457805191610a3083613217565b93610a3e60405195866131f5565b83855285848401011161066c575090610a5c91848085019101613095565b9038806109cd565b5080fd5b604051903d90823e3d90fd5b503461066c57604036600319011261066c57600435610a916130f3565b90610a9a613932565b808352602091600b835260ff600160408620015460d01c1615610ea357818452600583526001600160a01b038060408620541690813303610e8457610ade8461431b565b906001600160801b03808316908115918215610b04575b89610b01898989613797565b80f35b610b0c613932565b610b1588613326565b610e6c57610b3988600052600b6020526001600160a01b0360406000205416331490565b91821593848095610e5c575b610e3d57898c5260058b528560408d2054169380610e33575b610e0f5787156105c957610df757610b758961431b565b8181168311610dc5575091859493918a84610bfc8e9996610be58e6103bc600260408f610bba610ba486613513565b9e868352600b8c5284848420015460801c614343565b948152600b8a5220019182906001600160801b036001600160801b031983549260801b169116179055565b938401511692826040818351169201511690613286565b161115610d95575b898752600b8b52878a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8d88600160408d2001541694610c458186886142b3565b604051908152a48033141580610d8b575b610d1e575b5080610d14575b610ca1575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7610b0194604051858152a13880808080610af5565b16803b156104bc57604051636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b0392909216606483015282908290608490829084905af1610cfc575b8080610c67565b610d059061316f565b610d10578438610cf5565b8480fd5b50803b1515610c62565b803b1561053b57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03881660448201526001600160801b0386166064820152869182908290608490829084905af1610d77575b50610c5b565b610d809061316f565b610d10578438610d71565b50803b1515610c56565b898752600b8b526040872060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055610c04565b60405163287ecaef60e21b8152600481018b90526001600160801b038881166024830152919091166044820152606490fd5b6024896040519063d2aabcd960e01b82526004820152fd5b60648a8960405191632dcbf6b960e11b835260048301523360248301526044820152fd5b5083881415610b5e565b60405163216caf0d60e01b8152600481018b9052336024820152604490fd5b50610e668a61398e565b15610b45565b60248860405190634a5541ef60e01b82526004820152fd5b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b503461066c578060031936011261066c57602060405167016345785d8a00008152f35b503461066c57602036600319011261066c576020610f4c600435613513565b6001600160a01b0360405191168152f35b503461066c57602036600319011261066c5760ff600160406020936004358152600b855220015460d01c166040519015158152f35b503461066c57608036600319011261066c57610fac6130dd565b610fb46130f3565b906064359067ffffffffffffffff82116104c057366023830112156104c05781600401359284610fe385613217565b93610ff160405195866131f5565b8585523660248783010111610a645785610b019660246020930183880137850101526044359161347d565b503461066c57602036600319011261066c5760206106b4600435613446565b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105761107490613631565b60405190600581101561108957602092508152f35b602483634e487b7160e01b81526021600452fd5b503461066c5761014036600319011261066c576110b8613932565b6110c06133f3565b9064ffffffffff80421680845260c43582811681036111d15781018216602085015260e4359081831682036111d15701166040830152606435916001600160a01b039182841680940361066c57506084358015158091036111d15760a435908115158092036111d157602435948486168096036111d157600435958587168097036111d157604435906001600160801b0382168092036111d15760405197611167896131a0565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126111d157604051916111a1836131d9565b6101043591821682036111d157826111c99260209452610124358482015260e0820152613a72565b604051908152f35b600080fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760026040836001600160801b039360209552600b855220015416604051908152f35b503461066c57602036600319011261066c576112426130dd565b6001600160a01b03808354163381036112fc575081169081835260026020526001600160801b036040842054169081156112cb578161129c918486526002602052604086206001600160801b0319815416905533906142b3565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461066c57606036600319011261066c5767ffffffffffffffff6004358181116104bc5761135890369060040161313e565b916113616130f3565b9060449060443590811161053b5761137d90369060040161313e565b9094611387613932565b81810361177957865b81811061139b578780f35b6113a68183886133cd565b35906113b381858a6133cd565b356001600160801b03811681036111d1576113cc613932565b6113d583613326565b610654576113f983600052600b6020526001600160a01b0360406000205416331490565b80158080611769575b61062557848c5260056020526001600160a01b0360408d2054169180611756575b611729576001600160a01b038916156105c9576001600160801b038316156117115761144e8561431b565b6001600160801b0381166001600160801b038516116116df5750908b929161147586613513565b91868552600b806020526114c960026103bc61149a888360408c20015460801c614343565b918b8a528460205260408a20019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036114ed8160208401511692826040818351169201511690613286565b1611156116af575b8786526020526001600160a01b036001604087200154166115206001600160801b0386168d836142b3565b8b887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03604051946001600160801b038b1686521693a480331415806116a5575b611638575b508061162e575b6115b1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101611390565b6001600160a01b0381163b156104bc57604051636fd110e960e01b8152600481018690523360248201526001600160a01b038a811660448301526001600160801b03939093166064820152918391839160849183918591165af1611616575b8061157b565b61161f9061316f565b61162a578838611610565b8880fd5b50803b1515611576565b803b15610d1057604051636fd110e960e01b8152600481018890523360248201526001600160a01b038c1660448201526001600160801b0385166064820152859182908290608490829084905af1611691575b5061156f565b61169a9061316f565b6104c057833861168b565b50803b151561156a565b878652806020526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b1981541690556114f5565b60405163287ecaef60e21b8152600481018790526001600160801b038581166024830152919091166044820152606490fd5b6024856040519063d2aabcd960e01b82526004820152fd5b606485896001600160a01b038c60405193632dcbf6b960e11b855260048501523360248501521690820152fd5b50816001600160a01b038a161415611423565b506117738561398e565b15611402565b604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461066c57604036600319011261066c576117c96130dd565b602435908115158092036111d1576001600160a01b03169081331461183c5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b503461066c5761016036600319011261066c5761189b613932565b604051906118a8826131a0565b6118b06130dd565b82526118ba6130f3565b60208301526118c7613233565b60408301526001600160a01b039060643582811681036111d157606084015260843580151581036111d157608084015260a43580151581036111d15760a084015260603660c319011261066c5750604051611921816131bd565b64ffffffffff60c43581811681036111d157825260e43581811681036111d15760208301526101043590811681036111d157604082015260c08301526040610123193601126111d15760405191611977836131d9565b6101243591821682036111d157826111c99260209452610144358482015260e0820152613a72565b503461066c578060031936011261066c5760405190806004549160018360011c9260018516948515611aa4575b6020958686108114611a9057858852879493929187908215611a6e575050600114611a14575b5050611a00925003836131f5565b6109e36040519282849384528301906130b8565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b858310611a56575050611a00935082010138806119f2565b80548389018501528794508693909201918101611a3e565b9250935050611a0094915060ff191682840152151560051b82010138806119f2565b602483634e487b7160e01b81526022600452fd5b93607f16936119cc565b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057600160408364ffffffffff9360209552600b855220015460a01c16604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057611b3a90613631565b9060058210159081611b7b5760028314918215611b8f575b8215611b66575b6020836040519015158152f35b909150611b7b57506004602091143880611b59565b80634e487b7160e01b602492526021600452fd5b506003831491506000611b52565b503461066c57602036600319011261066c576004356001600160a01b03908181168091036104bc57818354163381036112fc575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b503461066c57602036600319011261066c57604051611c3881613183565b8181528160208201528160408201528160608201528160808201528160a08201528160c08201528160e08201528161010082015281610120820152610140611c7e6133f3565b9101526004358152600b60205260ff600160408320015460d01c1615611e56576004358152600b60205260408120611d57600260405192611cbe84613183565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a087015264ffffffffff8160a01c1660c0870152818160c81c16151560e0870152818160d01c16151561010087015260d81c16151561012085015201613412565b610140820152611d68600435613631565b6005811015611089579160026101a09314611e4b575b50610938610140604051926001600160a01b03815116845264ffffffffff602082015116602085015264ffffffffff60408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a085015264ffffffffff60c08201511660c085015260e0810151151560e0850152610100810151151561010085015261012081015115156101208501520151610140830190604090816001600160801b0391828151168552826020820151166020860152015116910152565b606082015238611d7e565b602460405162b8e7e760e51b81526004356004820152fd5b503461066c576020908160031936011261066c5760043567ffffffffffffffff8111610a6457611ea38391369060040161313e565b9190611ead613932565b83925b808410611ebb578480f35b611eca848284979596976133cd565b3594611ed4613932565b611edd86613326565b15611efa5760248660405190634a5541ef60e01b82526004820152fd5b611f038661354a565b61217757611f2786600052600b6020526001600160a01b0360406000205416331490565b1561215857611f358661357b565b95808552600b90818752611f4e60026040882001613412565b906001600160801b039283835116848b1610156121405781885280895260ff604089205460f01c161561212857611f9e8a858b611f9460409a9b9c9d9e83895116613286565b9601511690613286565b92828a52818b52868a20908b8b7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50845497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a1617865560038a821696871561210e575b01998516998a6001600160801b03198254161790556001600160a01b0380991698899360058652818e822054169889965260019d8e91200154169461204b8b85886142b3565b604080518a81526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78b604051858152a1813b6120af575b505050505001919093919293611eb0565b813b1561210a578994939192858094608493604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16120f6575b80808061209e565b6120ff9061316f565b610d105784876120ee565b8980fd5b60018101600160c81b60ff60c81b19825416179055612005565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b6024866040519063fe19f19f60e01b82526004820152fd5b503461066c57602080600319360112610a6457600435906121ae613932565b818352600b815260ff600160408520015460d01c1615610ea3576121d182613631565b600581101561235b57600481036121fa5760248360405190634a5541ef60e01b82526004820152fd5b6003810361221a576024836040519063fe19f19f60e01b82526004820152fd5b6002146121405761224182600052600b6020526001600160a01b0360406000205416331490565b1561233c57818352600b815260ff604084205460f01c161561212857818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b6122e4575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104bc57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612328575b806122b5565b6123319061316f565b6104bc578238612322565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602484634e487b7160e01b81526021600452fd5b503461066c57602036600319011261066c576004356001600160a01b03908181168091036104bc57818354163381036112fc5750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600954600019810190811161242c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066c57602036600319011261066c576124aa6130dd565b9080546001600160a01b03808216933385036124fc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461066c57602036600319011261066c576001600160a01b036125456130dd565b168015612562578160409160209352600683522054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b503461066c57602036600319011261066c576001600160a01b0360406020926004356126116109738260005260056020526001600160a01b0360406000205416151590565b815260058452205416604051908152f35b503461066c57602036600319011261066c576020610f4c6004356133a8565b503461066c578060031936011261066c5760206001600160a01b0360015416604051908152f35b503461066c57602036600319011261066c5760ff6001604060043593848152600b60205220015460d01c1615610710576107dd6020916139f7565b503461066c57602036600319011261066c5760043590818152600b60205260ff600160408320015460d01c1615610ea357806126de83613631565b926005841015612719576002602094036126ff575b50506040519015158152f35b8152600b8352604090205460f01c60ff16905038806126f3565b602482634e487b7160e01b81526021600452fd5b503461066c57602036600319011261066c5760043561274a613932565b61275381613326565b15612886576127618161398e565b156128665761276f816133a8565b61277882613446565b15908161285e575b8161284b575b50612833576020816127b87ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7936133a8565b90808552600783526001600160a01b0360408620926001600160a01b03199384815416905516918286526006845260408620600019815401905581865260058452604086209081541690558085604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a180f35b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151538612786565b839150612780565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066c576128c636613109565b60405191602083019383851067ffffffffffffffff8611176128f157610b019460405285845261347d565b634e487b7160e01b600052604160045260246000fd5b503461066c57602036600319011261066c5760206106b4600435613326565b503461066c57602080600319360112610a645760043590612945613932565b61294e82613326565b1561296b5760248260405190634a5541ef60e01b82526004820152fd5b906129758161354a565b612bac5761299981600052600b6020526001600160a01b0360406000205416331490565b15612866576129a78161357b565b818452600b83526129bd60026040862001613412565b926001600160801b0391828551168382161015612b9457838652600b825260ff604087205460f01c1615612b7c5792827ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce783612a328784604097612a288d9b612add9b8e5116613286565b9b01511690613286565b92848852600b825287868120947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84161788556003858216988915612b62575b01948d169c858e6001600160801b0319819854161790556001600160a01b038094169b8c94600589526001818e892054169d8e98600b8c52200154169685886142b3565b604080518b81526001600160801b0392831660208201529290911690820152606090a4604051848152a1823b612b11578480f35b823b15610d10576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612b53575b81818080808480f35b612b5c9061316f565b38612b4a565b60018101600160c81b60ff60c81b19825416179055612a99565b602484604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b6024906040519063fe19f19f60e01b82526004820152fd5b503461066c57602036600319011261066c576001600160801b0360406020926001600160a01b03612bf36130dd565b16815260028452205416604051908152f35b503461066c57610b01612c1736613109565b91612c2a612c2584336136b8565b6132b5565b613797565b503461066c578060031936011261066c576020600954604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057612c8690613631565b906005821015611b7b5760208215838115612ca7575b506040519015158152f35b600191501482612c9c565b503461066c57602036600319011261066c5760043590818152600b60205260ff600160408320015460d01c1615610ea357602091604082828152600b85522060ff815460f01c1680612d40575b612d17575b50506001600160801b0360405191168152f35b612d3992506001600160801b036002612d33920154169161357b565b90613286565b3880612d04565b5060ff600182015460c81c1615612cff565b503461066c57604036600319011261066c57612d6c6130dd565b602435906001600160a01b038080612d83856133a8565b16921691808314612e7757803314908115612e56575b5015612dec57828452600760205260408420826001600160a01b0319825416179055612dc4836133a8565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050845260086020526040842033855260205260ff60408520541638612d99565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b503461066c57602036600319011261066c576020610f4c600435613249565b503461066c578060031936011261066c5760405190806003549160018360011c9260018516948515612fba575b6020958686108114611a9057858852879493929187908215611a6e575050600114612f60575050611a00925003836131f5565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b858310612fa2575050611a00935082010138806119f2565b80548389018501528794508693909201918101612f8a565b93607f1693612f2d565b905034610a64576020366003190112610a64576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104bc57602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561306b575b8115613041575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861303a565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613033565b60005b8381106130a85750506000910152565b8181015183820152602001613098565b906020916130d181518092818552858086019101613095565b601f01601f1916010190565b600435906001600160a01b03821682036111d157565b602435906001600160a01b03821682036111d157565b60609060031901126111d1576001600160a01b039060043582811681036111d1579160243590811681036111d1579060443590565b9181601f840112156111d15782359167ffffffffffffffff83116111d1576020808501948460051b0101116111d157565b67ffffffffffffffff81116128f157604052565b610160810190811067ffffffffffffffff8211176128f157604052565b610100810190811067ffffffffffffffff8211176128f157604052565b6060810190811067ffffffffffffffff8211176128f157604052565b6040810190811067ffffffffffffffff8211176128f157604052565b90601f8019910116810190811067ffffffffffffffff8211176128f157604052565b67ffffffffffffffff81116128f157601f01601f191660200190565b604435906001600160801b03821682036111d157565b61326c6109738260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161329f57565b634e487b7160e01b600052601160045260246000fd5b156132bc57565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260ff60016040600020015460c81c1690565b1561336457565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b03604060002054166133ca81151561335d565b90565b91908110156133dd5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190613400826131bd565b60006040838281528260208201520152565b9060405161341f816131bd565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260ff60016040600020015460d81c1690565b906134a1939291613491612c2584336136b8565b61349c838383613797565b61468c565b156134a857565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460d01c161561071057600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260406000205460f81c90565b600090808252600b6020526040822091825464ffffffffff42818360c81c16116136295780600186015460a01c169182421015613613576135c89394955060a01c1680910390420361481f565b90828152600b6020526001600160801b03926135ee8460026040852001541680946148ff565b9283116135fb5750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b505091505090565b80600052600b602052604060002060ff600182015460c81c16600014613658575050600490565b805460f81c6136b1575460a01c64ffffffffff1642106136ab5761367b8161357b565b90600052600b6020526001600160801b0380600260406000200154169116106000146136a657600190565b600290565b50600090565b5050600390565b906001600160a01b0380806136cc846133a8565b169316918383149384156136ff575b5083156136e9575b50505090565b6136f591929350613249565b16143880806136e3565b909350600052600860205260406000208260005260205260ff6040600020541692386136db565b1561372d57565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b906137c092916137a6836133a8565b916001600160a01b03948593848094169687911614613726565b16908115806138c9576137d284613446565b1590816138c0575b50806138b7575b61389f57918084926138217ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661381a856133a8565b1614613726565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b508315156137e1565b905015386137da565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396457565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b0380604084205416928333149384156139d3575b505082156139c157505090565b9091506139ce3392613249565b161490565b60ff92945090604091815260086020528181203382526020522054169138806139b4565b80600052600b602052613a106002604060002001613412565b81600052600b602052604060002060ff600182015460c81c16600014613a4357506001600160801b039150602001511690565b5460f81c613a5557506133ca9061357b565b6133ca91506001600160801b036040818351169201511690613286565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156142a757600090614273575b613af391506001600160801b0360408501511690602060e086015101519161435e565b916001600160801b0383511660c082015190156142495764ffffffffff815116602082019064ffffffffff8251169081811161420957505064ffffffffff604091511691019064ffffffffff82511690818110156141c957505064ffffffffff8042169151169081811015614189575050600954926001600160801b0381511660405190613b80826131bd565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff6020840151169064ffffffffff604085015116906080870151151560a088015115159364ffffffffff6001600160a01b038a511697511660405197613bef89613183565b88526020880152604087015260608601526000608086015260a085015260c0840152600060e0840152600161010084015261012083015261014082015284600052600b60205260406000206001600160a01b038251166001600160a01b0319825416178155613c8664ffffffffff602084015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b604082015181547eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b169078ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006080880151151560f81b169460c81b1691161717178155600181016001600160a01b0360a0840151166001600160a01b0319825416178155613d7d64ffffffffff60c085015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b60e083015181546101008501516101208601517fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921692151560c81b79ff00000000000000000000000000000000000000000000000000169290921791151560d01b7aff0000000000000000000000000000000000000000000000000000169190911790151560d81b7bff00000000000000000000000000000000000000000000000000000016179055610140909101518051602082015160801b6001600160801b03199081166001600160801b03928316176002850155926040906003019201511682825416179055600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b03602083015116801561414557613ef8613ef28660005260056020526001600160a01b0360406000205416151590565b1561449d565b613f0185613446565b158061413c575b80614134575b61411c5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613f59613ef28860005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905586600052600582526040600020816001600160a01b0319825416179055866040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4868152a1613fe96001600160a01b036060840151166001600160801b038084511681602086015116011690309033906144e8565b6001600160801b03604082015116806140ed575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140e46001600160a01b03606089015116976080810151151560a08201511515906140ae6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b614116906001600160a01b036060850151166001600160a01b0360e086015151169033906144e8565b38613ffd565b60248560405190630da9b01360e01b82526004820152fd5b506000613f0e565b50801515613f08565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f4c23297000000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161429f575b8161428d602093836131f5565b810103126111d157613af39051613ad0565b3d9150614280565b6040513d6000823e3d90fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff8411176128f15761431992604052614553565b565b6133ca90614328816139f7565b90600052600b60205260026040600020015460801c90613286565b9190916001600160801b038080941691160191821161329f57565b9092916143696133f3565b936001600160801b03928381169182156144755767016345785d8a000080821161443e5780851161440757506143b3856143a48193866148ff565b169460208901958652846148ff565b1691846143ca604089019480865282875116614343565b1610156143f1576143e38491826143ec95511690613286565b91511690613286565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614488816131bd565b60008152600060208201526000604082015290565b156144a457565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176128f157614319926040525b6001600160a01b0316906145b360405161456c816131d9565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16145ad61465c565b916149ae565b805191821591848315614638575b5050509050156145ce5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b919381809450010312610a645782015190811515820361066c5750803880846145c1565b3d15614687573d9061466d82613217565b9161467b60405193846131f5565b82523d6000602084013e565b606090565b9290803b15614816576146f6916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906130b8565b03916000968791165af1908290826147b5575b505061478f5761471761465c565b8051908161478a5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d60201161480e575b816147d2602093836131f5565b81010312610a645751907fffffffff000000000000000000000000000000000000000000000000000000008216820361066c5750903880614709565b3d91506147c5565b50505050600190565b670de0b6b3a76400009160001983830992808302928380861095039480860395146148db578285101561489f57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156148e9570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461499d57670de0b6b3a7640000908183101561496657947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b91929015614a0f57508151156149c2575090565b3b156149cb5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015614a225750805190602001fd5b6105ad9060405191829162461bcd60e51b83526020600484015260248301906130b856fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615dcc90816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346142f85760403660031901126142f8576001600160a01b0360043516600435036142f857610056608061486e565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614946565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916147dd575b506001600160a01b03610117911680608052614b39565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614305576fffffffffffffffffffffffffffffffff916000916147be575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561430557600090614781575b6101e59150614c86565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561430557600091614752575b5060c0516fffffffffffffffffffffffffffffffff16801561473c576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614d82565b610120608001526040514660208201526bffffffffffffffffffffffff1960043560601b16604082015260243560548201526054815280608081011067ffffffffffffffff60808301111761431157608081016040526020815191012061041a602963ffffffff61032e6103078261016861ffff8860101c1606166155e2565b91601e604660ff6103248460146050848d60081c160601166155e2565b98160601166155e2565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261036e815180926020602488019101614826565b83017f2c0000000000000000000000000000000000000000000000000000000000000060248201526103aa825180936020602585019101614826565b017f252c00000000000000000000000000000000000000000000000000000000000060258201526103e5825180936020602785019101614826565b017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826148df565b6104526fffffffffffffffffffffffffffffffff6040608001511660ff61044b6001600160a01b0360805116614f69565b16906150d2565b6104666001600160a01b0360805116614946565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143055760249160009161471d575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa801561430557610528926000916146ee575b5064ffffffffff809116911661541d565b61012051610180519092916105b2602161054f60646105488187066158c3565b95046155e2565b6040519481610568879351809260208087019101614826565b820161057d8251809360208085019101614826565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836148df565b610100608001519260c060800151956101206080015197604051996105d68b61486e565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106a660c08401518451906159cf565b906109b361015c604051926106ba846148c3565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526107236040516106f38161488b565b60009052855160208701207fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4701490565b156146e6576090945b610735866155e2565b916040519586938493661e339034b21e9160c91b60208601526109818351958692610767846027840160208901614826565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107ae8551809660206042888701019101614826565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108b491889160f990910190602001614826565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094f91899161015190910190602001614826565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614826565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826148df565b6101008301526101208201526028610100830151604051906109d48261488b565b60008252610c7a61015c604051926109eb846148c3565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b610a2782615d49565b808211156146de5750945b610a3d8787016155e2565b91604051958693661e339034b21e9160c91b60208601528151610a67816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610aaa825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ba682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c3582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610c5c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101845201826148df565b610160840152016101808201526028602083015160405190610c9b8261488b565b60008252610ce561015c60405192610cb2846148c3565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b835201602082015261102060808301516030604051610d038161488b565b60008152610faa61015c60405194610d1a866148c3565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d4d86615ccb565b610d5682615d49565b808211156146d65750935b610d6d602886016155e2565b91604051978893661e339034b21e9160c91b60208601528151610d97816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dda825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ed682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f6582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610f8c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101865201846148df565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615068565b6060820152604051908161010081011067ffffffffffffffff6101008401111761431157610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161010084015191606081015194604051611176816148a7565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051966111d38861486e565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614311576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761431157611cb1611d129160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611868615996565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d0d60d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161199a60b88660208501936118da81605e840187614826565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261193f825180936020609385019101614826565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866148df565b6119a2615996565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a0881606b8a0184614826565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a4d825180936020608e85019101614826565b019082608e830152611a9160a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896148df565b611bd7610108611a9f615996565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b2b815180926020607387019101614826565b8201908760738301526076820152875190611b4a826096830188614826565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6148df565b611bdf615996565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614826565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cf382518093602060c485019101614826565b019160c483015260c78201520360b88101875201856148df565b615068565b92611d32611d1e614c14565b896020815191012090602081519101201490565b9788156146ad575b506040518060c081011067ffffffffffffffff60c0830111176143115760c08101604052609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614311576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146144885760405161218c8161488b565b60008152995b1561432757604051806101e081011067ffffffffffffffff6101e083011117614311576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761431157613b9f9c612e5a6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f2b9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612df68151809260208a8c019101614826565b8701612e0b8251809360208a85019101614826565b01612e1f8251809360208985019101614826565b01612e338251809360208885019101614826565b01612e478251809360208785019101614826565b01918201520360168101865201846148df565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e9f6026998260208c9451948593019101614826565b8901612eb48251809360208c85019101614826565b01612ec88251809360208b85019101614826565b01612edc8251809360208a85019101614826565b01612ef08251809360208985019101614826565b01612f048251809360208885019101614826565b01612f188251809360208785019101614826565b019182015203600d8101895201876148df565b6137be604c60e08301516101208401519361351a61314d6060604084015193015196612f578186615c0f565b9461314861012b604051612f6a816148c3565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fd4815180926020603787019101614826565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015282519261311891849161012090910190602001614826565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876148df565b615c0f565b9561332c61012b604051613160816148c3565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131ca815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261330782518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886148df565b6133368184615c77565b9261351561012b604051613349816148c3565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526133b3815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134f082518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856148df565b615c77565b906136f961012b60405161352d816148c3565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613597815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136d482518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836148df565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261375f815180926020604589019101614826565b8401613775825180936020604585019101614826565b0161378a825180936020604585019101614826565b0161379f825180936020604585019101614826565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826148df565b613a9e61019a6101408401516101a0850151906137ff6137f96137f36137ed60e060408b01519a0151946155e2565b946155e2565b976155e2565b916155e2565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061399a815180926020858a019101614826565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d2200000000000000000061013288015261014996613a048251809360208b85019101614826565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a478251809360208985019101614826565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a8a8251809360208785019101614826565b01918201520361017a8101855201836148df565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b2a815180926020607b89019101614826565b8401613b40825180936020607b85019101614826565b01613b55825180936020607b85019101614826565b01613b6a825180936020607b85019101614826565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826148df565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916142ba575b6142b661424f614154614245609487613d3b6089613c198a614946565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613c60815180926020604088019101614826565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613cc5825180936020606385019101614826565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d06825180936020608685019101614826565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826148df565b6101a05160a05161403e61017e613d536024356155e2565b9360a060800151613d6e6001600160a01b0360805116614946565b90604051968793613f2b60208601987f54686973204e465420726570726573656e74732061207061796d656e742073748a527f7265616d20696e2061205361626c696572205632200000000000000000000000604088015282516020840190613ddb8160558b0184614826565b8801947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613e658260b183018a614826565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ea082518093602060c385019101614826565b01613ed97f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614826565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613f1782518093602060d185019101614826565b019260d184015251809360d5840190614826565b019060d5820152613f4682518093602060df85019101614826565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560e38201527f204e4654206d616b657320746865206e6577206f776e657220746865207265636101038201527f697069656e74206f66207468652073747265616d2e205468652066756e6473206101238201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e206101438201527f666f72207468652070726576696f757320726563697069656e742e00000000006101638201520361015e8101855201836148df565b6101a051906141af6140516024356155e2565b916140d0602d604051809560208201976a029b0b13634b2b9102b19160ad1b8952614086815180926020602b87019101614826565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140c18251809360208785019101614826565b0103600d8101865201846148df565b610160516140dd90615733565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a015261411e815180926020602e8d019101614826565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614826565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614826565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614210825180936020609285019101614826565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826148df565b60e0819052615733565b6142a2603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142928151809260208686019101614826565b810103601d8101845201826148df565b604051918291602083526020830190614849565b0390f35b90506020813d6020116142fd575b816142d5602093836148df565b810103126142f85751906001600160a01b03821682036142f85790614154613bfc565b600080fd5b3d91506142c8565b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761431157610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123df565b604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612192565b6146cf9198506146bb614c4d565b906020815191012090602081519101201490565b9638611d3a565b905093610d61565b905094610a32565b60d09461072c565b614710915060203d602011614716575b61470881836148df565b810190614929565b38610517565b503d6146fe565b614736915060203d6020116147165761470881836148df565b386104c1565b634e487b7160e01b600052601260045260246000fd5b614774915060203d60201161477a575b61476c81836148df565b810190614901565b3861023f565b503d614762565b506020813d6020116147b6575b8161479b602093836148df565b810103126142f8575160058110156142f8576101e5906101db565b3d915061478e565b6147d7915060203d60201161477a5761476c81836148df565b38610181565b90506020813d60201161481e575b816147f8602093836148df565b810103126142f857516001600160a01b03811681036142f8576001600160a01b03610100565b3d91506147eb565b60005b8381106148395750506000910152565b8181015183820152602001614829565b9060209161486281518092818552858086019101614826565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761431157604052565b6020810190811067ffffffffffffffff82111761431157604052565b6060810190811067ffffffffffffffff82111761431157604052565b6040810190811067ffffffffffffffff82111761431157604052565b90601f8019910116810190811067ffffffffffffffff82111761431157604052565b908160209103126142f857516fffffffffffffffffffffffffffffffff811681036142f85790565b908160209103126142f8575164ffffffffff811681036142f85790565b6001600160a01b03166040519061495c826148a7565b602a8252602082016040368237825115614a755760309053815160019060011015614a7557607860218401536029905b8082116149fa57505061499c5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b9091600f81166010811015614a60577f3031323334353637383961626364656600000000000000000000000000000000901a614a3684866158b2565b5360041c918015614a4b57600019019061498c565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161431157601f01601f191660200190565b3d15614ad2573d90614ab882614a8b565b91614ac660405193846148df565b82523d6000602084013e565b606090565b6020818303126142f85780519067ffffffffffffffff82116142f8570181601f820112156142f8578051614b0a81614a8b565b92614b1860405194856148df565b818452602082840101116142f857614b369160208085019101614826565b90565b6000809160405160208101906395d89b4160e01b825260048152614b5c816148c3565b51915afa614b68614aa7565b90158015614c08575b614bce5780602080614b8893518301019101614ad7565b601e815111600014614b365750604051614ba1816148c3565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614bdb816148c3565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b71565b60405190614c21826148c3565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614c5a826148c3565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614d6c5760048103614ca05750614b36614c4d565b60038103614ce25750604051614cb5816148c3565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d245750604051614cf7816148c3565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d3357614b36614c14565b604051614d3f816148c3565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660409081516395d89b4160e01b8152600081600481855afa908115614f5e57600091614f3b575b50614e178351614dc1816148c3565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020918201528251908301207fc66b376a19264d832c1bc254000c18944ca5aa57ed50f4ea637c4da424d4c3bb1490565b15614e5557505051614e28816148c3565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b614eb98351614e63816148c3565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020918201528251908301207f6ab655856fa5352de8c05542b1937ac63c59342da992602767c02734cc5391651490565b15614ef757505051614eca816148c3565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b614f379083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614849565b0390fd5b614f5891503d806000833e614f5081836148df565b810190614ad7565b38614db2565b83513d6000823e3d90fd5b60405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614fa1816148c3565b6000928392839251915afa614fb4614aa7565b9080614feb575b15614fe757602081805181010312614fe357602001519060ff82168203614fe0575090565b80fd5b5080fd5b5090565b506020815114614fbb565b60405190615003826148c3565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061503c826148c3565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906150d092949360405195869260209461508a81518092888089019101614826565b840161509e82518093888085019101614826565b016150b182518093878085019101614826565b016150c482518093868085019101614826565b010380855201836148df565b565b80156153e257600091806153bd575090505b600190808281101561514e575050506150fb61502f565b614b36602260405183615118829551809260208086019101614826565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826148df565b66038d7ea4c6800011156153605760409081519060a0820182811067ffffffffffffffff821117614311578084526151858161488b565b600081528252825190615197826148c3565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516151d1816148c3565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615208816148c3565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615240816148c3565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615334575b50845194615287866148c3565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b8281106153215750505050615302615308917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526152fd866148c3565b6155e2565b916158c3565b916005851015614a7557614b369460051b015192615068565b81810184015188820185015283016152b8565b9591926103e89081851061535757508680916064600a8704069504930196615275565b9392965061527a565b505061536a614ff6565b614b36602860405183615387829551809260208086019101614826565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826148df565b600a0a9182156153ce5750046150e4565b80634e487b7160e01b602492526012600452fd5b50506040516153f0816148c3565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b6201518091030480615485575061543261502f565b614b3660266040518361544f829551809260208086019101614826565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826148df565b61270f8111615554576001810361551157614b3660206154d96040516154aa816148c3565b600481527f204461790000000000000000000000000000000000000000000000000000000083820152936155e2565b60405193816154f18693518092868087019101614826565b820161550582518093868085019101614826565b010380845201826148df565b614b3660206154d9604051615525816148c3565b600581527f204461797300000000000000000000000000000000000000000000000000000083820152936155e2565b5061555d614ff6565b614b36602a6040518361557a829551809260208086019101614826565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826148df565b906155ba82614a8b565b6155c760405191826148df565b82815280926155d8601f1991614a8b565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615725575b506d04ee2d6d415b85acef810000000080831015615716575b50662386f26fc1000080831015615707575b506305f5e100808310156156f8575b50612710808310156156e9575b5060648210156156d9575b600a809210156156cf575b60019081602161567a600187016155b0565b95860101905b61568c575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156156ca57919082615680565b615685565b9160010191615668565b919060646002910491019161565d565b60049193920491019138615652565b60089193920491019138615645565b60109193920491019138615636565b60209193920491019138615624565b60409350810491503861560b565b80511561589e57604051615746816148a7565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116158885760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103615888576157e5906002959492951b6155b0565b936020850193839284518501935b84811061583557505050505060039051068060011461582257600214615817575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151868201530195939291906157f3565b634e487b7160e01b600052601160045260246000fd5b506040516158ab8161488b565b6000815290565b908151811015614a75570160200190565b806158d557506040516158ab8161488b565b600a81101561593a576158e7906155e2565b614b36602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261592a8151809260208686019101614826565b81010360028101845201826148df565b615943906155e2565b614b36602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159868151809260208686019101614826565b81010360018101845201826148df565b604051906159a3826148c3565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615c01576159dd615996565b9061271090810390811161588857614b36916159fb610136926155e2565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615a87815180926020605788019101614826565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615b0f82518093602060a785019101614826565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615b7082518093602060d585019101614826565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826148df565b50506040516158ab8161488b565b60306150d0919392936040519481615c31879351809260208087019101614826565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615c688251809360208785019101614826565b010360108101855201836148df565b60256150d0919392936040519481615c99879351809260208087019101614826565b820164010714051160dd1b6020820152615cbc8251809360208785019101614826565b010360058101855201836148df565b60009080518015615d4157906000916000915b818310615cf057505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615d2387856158b2565b511614615d39575b600d01936001019190615cde565b849350615d2b565b505050600090565b60009080518015615d4157906000916000915b818310615d6e5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615da187856158b2565b511614615db7575b601001936001019190615d5c565b849350615da956fea164736f6c6343000817000a"; From ca8a8e4b68367523a7c12e2277e7fd9846228c84 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 6 Jan 2024 14:30:06 +0530 Subject: [PATCH 032/132] perf: remove unchecked in for loop --- src/abstracts/SablierV2Lockup.sol | 14 ++------------ src/libraries/Helpers.sol | 7 +------ src/libraries/SVGElements.sol | 3 +-- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 29a86b432..8c71af7af 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -175,14 +175,9 @@ abstract contract SablierV2Lockup is function cancelMultiple(uint256[] calldata streamIds) external override noDelegateCall { // Iterate over the provided array of stream ids and cancel each stream. uint256 count = streamIds.length; - for (uint256 i = 0; i < count;) { + for (uint256 i = 0; i < count; ++i) { // Effects and Interactions: cancel the stream. cancel(streamIds[i]); - - // Increment the loop iterator. - unchecked { - i += 1; - } } } @@ -361,14 +356,9 @@ abstract contract SablierV2Lockup is } // Iterate over the provided array of stream ids and withdraw from each stream. - for (uint256 i = 0; i < streamIdsCount;) { + for (uint256 i = 0; i < streamIdsCount; ++i) { // Checks, Effects and Interactions: check the parameters and make the withdrawal. withdraw(streamIds[i], to, amounts[i]); - - // Increment the loop iterator. - unchecked { - i += 1; - } } } diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index a0c195fb5..8a6c48065 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -177,7 +177,7 @@ library Helpers { // 1. Calculate the sum of all segment amounts. // 2. Check that the milestones are ordered. uint256 count = segments.length; - for (uint256 index = 0; index < count;) { + for (uint256 index = 0; index < count; ++index) { // Add the current segment amount to the sum. segmentAmountsSum += segments[index].amount; @@ -191,11 +191,6 @@ library Helpers { // Make the current milestone the previous milestone of the next loop iteration. previousMilestone = currentMilestone; - - // Increment the loop iterator. - unchecked { - index += 1; - } } // Checks: the last milestone is in the future. diff --git a/src/libraries/SVGElements.sol b/src/libraries/SVGElements.sol index 0c8461dbe..eb02cc694 100644 --- a/src/libraries/SVGElements.sol +++ b/src/libraries/SVGElements.sol @@ -239,12 +239,11 @@ library SVGElements { unchecked { uint256 charWidth = largeFont ? 16 : 13; uint256 semicolonIndex; - for (uint256 i = 0; i < length;) { + for (uint256 i = 0; i < length; ++i) { if (bytes(text)[i] == ";") { semicolonIndex = i; } width += charWidth; - i += 1; } // Account for escaped characters (such as ≥). From f2875bfc6d0e0212d119d01e556cf3a964340541 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 11 Jan 2024 16:44:58 +0200 Subject: [PATCH 033/132] chore: use pragma solidity >=0.8.22 --- .github/workflows/multibuild.yml | 2 +- .solhint.json | 2 +- script/Base.s.sol | 2 +- script/DeployComptroller.s.sol | 2 +- script/DeployCore.s.sol | 2 +- script/DeployCore2.s.sol | 2 +- script/DeployDeterministicComptroller.s.sol | 2 +- script/DeployDeterministicCore.s.sol | 2 +- script/DeployDeterministicCore2.s.sol | 2 +- script/DeployDeterministicLockupDynamic.s.sol | 2 +- script/DeployDeterministicLockupLinear.s.sol | 2 +- script/DeployDeterministicNFTDescriptor.s.sol | 2 +- script/DeployLockupDynamic.s.sol | 2 +- script/DeployLockupLinear.s.sol | 2 +- script/DeployNFTDescriptor.s.sol | 2 +- script/GenerateSVG.s.sol | 2 +- script/Init.s.sol | 2 +- src/SablierV2Comptroller.sol | 2 +- src/SablierV2LockupDynamic.sol | 2 +- src/SablierV2LockupLinear.sol | 2 +- src/SablierV2NFTDescriptor.sol | 2 +- src/abstracts/Adminable.sol | 2 +- src/abstracts/NoDelegateCall.sol | 2 +- src/abstracts/SablierV2Base.sol | 2 +- src/abstracts/SablierV2Lockup.sol | 2 +- src/interfaces/IAdminable.sol | 2 +- src/interfaces/ISablierV2Base.sol | 2 +- src/interfaces/ISablierV2Comptroller.sol | 2 +- src/interfaces/ISablierV2Lockup.sol | 2 +- src/interfaces/ISablierV2LockupDynamic.sol | 2 +- src/interfaces/ISablierV2LockupLinear.sol | 2 +- src/interfaces/ISablierV2NFTDescriptor.sol | 2 +- src/interfaces/hooks/ISablierV2Recipient.sol | 2 +- src/interfaces/hooks/ISablierV2Sender.sol | 2 +- src/libraries/Errors.sol | 2 +- src/libraries/Helpers.sol | 2 +- src/libraries/NFTSVG.sol | 2 +- src/libraries/SVGElements.sol | 2 +- src/types/DataTypes.sol | 2 +- test/Base.t.sol | 2 +- test/fork/Fork.t.sol | 2 +- test/fork/LockupDynamic.t.sol | 2 +- test/fork/LockupLinear.t.sol | 2 +- test/fork/assets/DAI.t.sol | 2 +- test/fork/assets/EURS.t.sol | 2 +- test/fork/assets/SHIB.t.sol | 2 +- test/fork/assets/USDC.t.sol | 2 +- test/fork/assets/USDT.t.sol | 2 +- test/integration/Integration.t.sol | 2 +- .../concrete/comptroller/protocol-fees/protocolFees.t.sol | 2 +- .../concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol | 2 +- test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol | 2 +- test/integration/concrete/lockup-dynamic/constructor.t.sol | 2 +- .../lockup-dynamic/create-with-deltas/createWithDeltas.t.sol | 2 +- .../create-with-milestones/createWithMilestones.t.sol | 2 +- .../concrete/lockup-dynamic/get-range/getRange.t.sol | 2 +- .../concrete/lockup-dynamic/get-segments/getSegments.t.sol | 2 +- .../concrete/lockup-dynamic/get-stream/getStream.t.sol | 2 +- .../lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../concrete/lockup-dynamic/token-uri/tokenURI.t.sol | 2 +- .../withdrawable-amount-of/withdrawableAmountOf.t.sol | 2 +- test/integration/concrete/lockup-linear/LockupLinear.t.sol | 2 +- test/integration/concrete/lockup-linear/constructor.t.sol | 2 +- .../create-with-durations/createWithDurations.t.sol | 2 +- .../lockup-linear/create-with-range/createWithRange.t.sol | 2 +- .../concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol | 2 +- .../integration/concrete/lockup-linear/get-range/getRange.t.sol | 2 +- .../concrete/lockup-linear/get-stream/getStream.t.sol | 2 +- .../lockup-linear/streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../integration/concrete/lockup-linear/token-uri/tokenURI.t.sol | 2 +- .../withdrawable-amount-of/withdrawableAmountOf.t.sol | 2 +- test/integration/concrete/lockup/burn/burn.t.sol | 2 +- .../concrete/lockup/cancel-multiple/cancelMultiple.t.sol | 2 +- test/integration/concrete/lockup/cancel/cancel.t.sol | 2 +- .../lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol | 2 +- test/integration/concrete/lockup/get-asset/getAsset.t.sol | 2 +- .../lockup/get-deposited-amount/getDepositedAmount.t.sol | 2 +- test/integration/concrete/lockup/get-end-time/getEndTime.t.sol | 2 +- .../concrete/lockup/get-recipient/getRecipient.t.sol | 2 +- .../concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol | 2 +- test/integration/concrete/lockup/get-sender/getSender.t.sol | 2 +- .../concrete/lockup/get-start-time/getStartTime.t.sol | 2 +- .../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol | 2 +- .../concrete/lockup/is-cancelable/isCancelable.t.sol | 2 +- test/integration/concrete/lockup/is-cold/isCold.t.sol | 2 +- test/integration/concrete/lockup/is-depleted/isDepleted.t.sol | 2 +- test/integration/concrete/lockup/is-stream/isStream.t.sol | 2 +- .../concrete/lockup/is-transferable/isTransferable.t.sol | 2 +- test/integration/concrete/lockup/is-warm/isWarm.t.sol | 2 +- .../concrete/lockup/protocol-revenues/protocolRevenues.t.sol | 2 +- .../lockup/refundable-amount-of/refundableAmountOf.t.sol | 2 +- test/integration/concrete/lockup/renounce/renounce.t.sol | 2 +- .../concrete/lockup/set-comptroller/setComptroller.t.sol | 2 +- .../concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol | 2 +- test/integration/concrete/lockup/status-of/statusOf.t.sol | 2 +- .../concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../concrete/lockup/transfer-from/transferFrom.t.sol | 2 +- test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol | 2 +- .../withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol | 2 +- test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol | 2 +- .../concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol | 2 +- test/integration/concrete/lockup/withdraw/withdraw.t.sol | 2 +- .../lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol | 2 +- test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol | 2 +- .../concrete/nft-descriptor/generateAccentColor.t.sol | 2 +- .../concrete/nft-descriptor/map-symbol/mapSymbol.t.sol | 2 +- .../nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol | 2 +- .../nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol | 2 +- test/integration/fuzz/comptroller/setProtocolFee.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/withdraw.t.sol | 2 +- test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol | 2 +- test/integration/fuzz/lockup-linear/LockupLinear.t.sol | 2 +- test/integration/fuzz/lockup-linear/createWithDurations.t.sol | 2 +- test/integration/fuzz/lockup-linear/createWithRange.t.sol | 2 +- test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol | 2 +- test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol | 2 +- test/integration/fuzz/lockup/cancel.t.sol | 2 +- test/integration/fuzz/lockup/cancelMultiple.t.sol | 2 +- test/integration/fuzz/lockup/getWithdrawnAmount.t.sol | 2 +- test/integration/fuzz/lockup/refundableAmountOf.t.sol | 2 +- test/integration/fuzz/lockup/withdraw.t.sol | 2 +- test/integration/fuzz/lockup/withdrawMax.t.sol | 2 +- test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol | 2 +- test/integration/fuzz/lockup/withdrawMultiple.t.sol | 2 +- test/integration/shared/lockup-dynamic/LockupDynamic.t.sol | 2 +- test/integration/shared/lockup-dynamic/createWithDeltas.t.sol | 2 +- .../shared/lockup-dynamic/createWithMilestones.t.sol | 2 +- test/integration/shared/lockup-linear/LockupLinear.t.sol | 2 +- test/integration/shared/lockup-linear/createWithDurations.t.sol | 2 +- test/integration/shared/lockup-linear/createWithRange.t.sol | 2 +- test/integration/shared/lockup/Lockup.t.sol | 2 +- test/integration/shared/lockup/cancel.t.sol | 2 +- test/integration/shared/lockup/cancelMultiple.t.sol | 2 +- test/integration/shared/lockup/getWithdrawnAmount.t.sol | 2 +- test/integration/shared/lockup/streamedAmountOf.t.sol | 2 +- test/integration/shared/lockup/withdraw.t.sol | 2 +- test/integration/shared/lockup/withdrawMax.t.sol | 2 +- test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol | 2 +- test/integration/shared/lockup/withdrawMultiple.t.sol | 2 +- test/integration/shared/lockup/withdrawableAmountOf.t.sol | 2 +- test/invariant/Invariant.t.sol | 2 +- test/invariant/Lockup.t.sol | 2 +- test/invariant/LockupDynamic.t.sol | 2 +- test/invariant/LockupLinear.t.sol | 2 +- test/invariant/handlers/BaseHandler.sol | 2 +- test/invariant/handlers/ComptrollerHandler.sol | 2 +- test/invariant/handlers/LockupDynamicCreateHandler.sol | 2 +- test/invariant/handlers/LockupDynamicHandler.sol | 2 +- test/invariant/handlers/LockupHandler.sol | 2 +- test/invariant/handlers/LockupLinearCreateHandler.sol | 2 +- test/invariant/handlers/LockupLinearHandler.sol | 2 +- test/invariant/stores/LockupStore.sol | 2 +- test/invariant/stores/TimestampStore.sol | 2 +- test/mocks/AdminableMock.sol | 2 +- test/mocks/NFTDescriptorMock.sol | 2 +- test/mocks/Noop.sol | 2 +- test/mocks/erc20/ERC20Bytes32.sol | 2 +- test/mocks/erc20/ERC20MissingReturn.sol | 2 +- test/mocks/hooks/GoodRecipient.sol | 2 +- test/mocks/hooks/GoodSender.sol | 2 +- test/mocks/hooks/ReentrantRecipient.sol | 2 +- test/mocks/hooks/ReentrantSender.sol | 2 +- test/mocks/hooks/RevertingRecipient.sol | 2 +- test/mocks/hooks/RevertingSender.sol | 2 +- test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol | 2 +- test/unit/concrete/comptroller/Comptroller.t.sol | 2 +- test/unit/concrete/comptroller/constructor.t.sol | 2 +- test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol | 2 +- test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol | 2 +- test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol | 2 +- test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol | 2 +- .../concrete/nft-descriptor/calculateStreamedPercentage.t.sol | 2 +- test/unit/concrete/nft-descriptor/generateAttributes.t.sol | 2 +- test/unit/concrete/nft-descriptor/generateDescription.t.sol | 2 +- test/unit/concrete/nft-descriptor/generateName.t.sol | 2 +- test/unit/concrete/nft-descriptor/generateSVG.t.sol | 2 +- test/unit/concrete/nft-descriptor/hourglass.t.sol | 2 +- test/unit/concrete/nft-descriptor/stringifyCardType.t.sol | 2 +- .../concrete/nft-descriptor/stringifyFractionalAmount.t.sol | 2 +- test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol | 2 +- test/unit/concrete/nft-descriptor/stringifyStatus.t.sol | 2 +- test/unit/fuzz/transferAdmin.t.sol | 2 +- test/unit/shared/Adminable.t.sol | 2 +- test/utils/Assertions.sol | 2 +- test/utils/Calculations.sol | 2 +- test/utils/Constants.sol | 2 +- test/utils/Defaults.sol | 2 +- test/utils/DeployOptimized.sol | 2 +- test/utils/Events.sol | 2 +- test/utils/Fuzzers.sol | 2 +- test/utils/Precompiles.sol | 2 +- test/utils/Precompiles.t.sol | 2 +- test/utils/Types.sol | 2 +- test/utils/Utils.sol | 2 +- 198 files changed, 198 insertions(+), 198 deletions(-) diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index 2b872f81a..ee53e7087 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -21,6 +21,6 @@ jobs: - name: "Check that V2 Core can be built with multiple Solidity versions" uses: "PaulRBerg/foundry-multibuild@v1" with: - min: "0.8.19" + min: "0.8.22" max: "0.8.23" skip-test: "true" diff --git a/.solhint.json b/.solhint.json index 31a4d5b8c..713a70b3f 100644 --- a/.solhint.json +++ b/.solhint.json @@ -3,7 +3,7 @@ "rules": { "avoid-low-level-calls": "off", "code-complexity": ["error", 9], - "compiler-version": ["error", ">=0.8.19"], + "compiler-version": ["error", ">=0.8.22"], "contract-name-camelcase": "off", "const-name-snakecase": "off", "custom-errors": "off", diff --git a/script/Base.s.sol b/script/Base.s.sol index c7cb10298..1bdd306d2 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable no-console -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/script/DeployComptroller.s.sol b/script/DeployComptroller.s.sol index cfeb4769c..06aa513bd 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.22 <0.9.0; import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index af004c481..8e6102348 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.22 <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 6c5bd2bb5..4bdfca0b4 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.22 <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 9c4d8d8eb..aa46db9f0 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.22 <0.9.0; import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index d6c00ad44..4f26d7e12 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.22 <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 77d84ad3c..312ccf98d 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.22 <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 b57a727e2..b0cdce438 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.22 <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 921429799..188fc6d7e 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.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index 7998d4f28..f7a72bff2 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.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.22 <0.9.0; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index 6e59a05a6..e42c7ebde 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.22 <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 b3af99d1b..a53ced857 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.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index a84ebb90d..6f3019171 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.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.22 <0.9.0; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; diff --git a/script/GenerateSVG.s.sol b/script/GenerateSVG.s.sol index df3bbc9d7..1ee151a7b 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.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/script/Init.s.sol b/script/Init.s.sol index f3169f902..506dbc05b 100644 --- a/script/Init.s.sol +++ b/script/Init.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.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; diff --git a/src/SablierV2Comptroller.sol b/src/SablierV2Comptroller.sol index 696866d0d..7be16b172 100644 --- a/src/SablierV2Comptroller.sol +++ b/src/SablierV2Comptroller.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index c97b00008..730c30074 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index bab2aee55..5a5ad8adb 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 741bb51ce..5601cc2e1 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable max-line-length,quotes -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/src/abstracts/Adminable.sol b/src/abstracts/Adminable.sol index 6cbd952c0..26171c59c 100644 --- a/src/abstracts/Adminable.sol +++ b/src/abstracts/Adminable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IAdminable } from "../interfaces/IAdminable.sol"; import { Errors } from "../libraries/Errors.sol"; diff --git a/src/abstracts/NoDelegateCall.sol b/src/abstracts/NoDelegateCall.sol index c01be8734..615297067 100644 --- a/src/abstracts/NoDelegateCall.sol +++ b/src/abstracts/NoDelegateCall.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { Errors } from "../libraries/Errors.sol"; diff --git a/src/abstracts/SablierV2Base.sol b/src/abstracts/SablierV2Base.sol index 356777840..a93ca4277 100644 --- a/src/abstracts/SablierV2Base.sol +++ b/src/abstracts/SablierV2Base.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 8c71af7af..1a04271a3 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; diff --git a/src/interfaces/IAdminable.sol b/src/interfaces/IAdminable.sol index e5ee09561..62a13d1a7 100644 --- a/src/interfaces/IAdminable.sol +++ b/src/interfaces/IAdminable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; /// @title IAdminable /// @notice Contract module that provides a basic access control mechanism, with an admin that can be diff --git a/src/interfaces/ISablierV2Base.sol b/src/interfaces/ISablierV2Base.sol index ec7bcdbaf..84b6d10cd 100644 --- a/src/interfaces/ISablierV2Base.sol +++ b/src/interfaces/ISablierV2Base.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/src/interfaces/ISablierV2Comptroller.sol b/src/interfaces/ISablierV2Comptroller.sol index d7b779d69..ca5a718af 100644 --- a/src/interfaces/ISablierV2Comptroller.sol +++ b/src/interfaces/ISablierV2Comptroller.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 15ab4f511..90271b846 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index d117d9c8a..e60cb3fee 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index be1edebd3..95ecd1f16 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/src/interfaces/ISablierV2NFTDescriptor.sol b/src/interfaces/ISablierV2NFTDescriptor.sol index b3bb98864..f2f757fdf 100644 --- a/src/interfaces/ISablierV2NFTDescriptor.sol +++ b/src/interfaces/ISablierV2NFTDescriptor.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/src/interfaces/hooks/ISablierV2Recipient.sol b/src/interfaces/hooks/ISablierV2Recipient.sol index 268f04238..d6e029af6 100644 --- a/src/interfaces/hooks/ISablierV2Recipient.sol +++ b/src/interfaces/hooks/ISablierV2Recipient.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; /// @title ISablierV2Recipient /// @notice Interface for recipient contracts capable of reacting to cancellations, renouncements, and withdrawals. diff --git a/src/interfaces/hooks/ISablierV2Sender.sol b/src/interfaces/hooks/ISablierV2Sender.sol index 6e8220b93..632e13065 100644 --- a/src/interfaces/hooks/ISablierV2Sender.sol +++ b/src/interfaces/hooks/ISablierV2Sender.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; /// @title ISablierV2Sender /// @notice Interface for sender contracts capable of reacting to withdrawals. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 4332ab068..bf9548520 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 8a6c48065..cfc9e2d54 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; diff --git a/src/libraries/NFTSVG.sol b/src/libraries/NFTSVG.sol index 807b03e3b..dedd93cd1 100644 --- a/src/libraries/NFTSVG.sol +++ b/src/libraries/NFTSVG.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable quotes -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/src/libraries/SVGElements.sol b/src/libraries/SVGElements.sol index eb02cc694..92f1bbdd0 100644 --- a/src/libraries/SVGElements.sol +++ b/src/libraries/SVGElements.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // solhint-disable max-line-length,quotes -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 8ea369cb0..1120d6e8f 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD2x18 } from "@prb/math/src/UD2x18.sol"; diff --git a/test/Base.t.sol b/test/Base.t.sol index bc26e18ff..84910fd2f 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/fork/Fork.t.sol b/test/fork/Fork.t.sol index 257f93aaf..32cd0ec83 100644 --- a/test/fork/Fork.t.sol +++ b/test/fork/Fork.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 54c671cb4..9219af5e7 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index e0fa7c6a6..0ed6ca9f2 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; diff --git a/test/fork/assets/DAI.t.sol b/test/fork/assets/DAI.t.sol index 3fdb579c3..6089fbca6 100644 --- a/test/fork/assets/DAI.t.sol +++ b/test/fork/assets/DAI.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/fork/assets/EURS.t.sol b/test/fork/assets/EURS.t.sol index 969daa1bc..3586f5514 100644 --- a/test/fork/assets/EURS.t.sol +++ b/test/fork/assets/EURS.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/fork/assets/SHIB.t.sol b/test/fork/assets/SHIB.t.sol index e8d321a03..d67aeef1a 100644 --- a/test/fork/assets/SHIB.t.sol +++ b/test/fork/assets/SHIB.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/fork/assets/USDC.t.sol b/test/fork/assets/USDC.t.sol index ea79ae380..c76a4c2cd 100644 --- a/test/fork/assets/USDC.t.sol +++ b/test/fork/assets/USDC.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/fork/assets/USDT.t.sol b/test/fork/assets/USDT.t.sol index 421144ca1..c88181bf8 100644 --- a/test/fork/assets/USDT.t.sol +++ b/test/fork/assets/USDT.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index 4d5179717..8bfe557b2 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol b/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol index d7af61c96..2efdc66a1 100644 --- a/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol +++ b/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol index bf16f79ee..fff14e693 100644 --- a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol +++ b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index c5ff9c6e7..f4e92bdde 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index 01cb03c8b..f27859db7 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SablierV2LockupDynamic } from "src/SablierV2LockupDynamic.sol"; diff --git a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol b/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol index cd79d99a4..4affdbb97 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; diff --git a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol b/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol index 46e62461a..5a7b028b6 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol b/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol index 892864707..630a1c295 100644 --- a/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol +++ b/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol b/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol index f46eee599..b94535d00 100644 --- a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol +++ b/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol index 5c01e7898..0c9e1f110 100644 --- a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol index 922cf3fc7..040dd310b 100644 --- a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol index 80f06f345..c096e584e 100644 --- a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // solhint-disable max-line-length,no-console,quotes -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { console2 } from "forge-std/src/console2.sol"; import { LibString } from "solady/src/utils/LibString.sol"; diff --git a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol index f6532410a..66290ad29 100644 --- a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; import { WithdrawableAmountOf_Integration_Concrete_Test } from diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index e347f38a7..02a7b9c5b 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index 12e7fb8f7..9feb34691 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SablierV2LockupLinear } from "src/SablierV2LockupLinear.sol"; diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 02f9c53ab..f01eb9415 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol b/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol index 65a988b08..14c5f4018 100644 --- a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol b/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol index 2a22e894b..3207a55f2 100644 --- a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol +++ b/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup-linear/get-range/getRange.t.sol b/test/integration/concrete/lockup-linear/get-range/getRange.t.sol index de45282ca..6e71a3522 100644 --- a/test/integration/concrete/lockup-linear/get-range/getRange.t.sol +++ b/test/integration/concrete/lockup-linear/get-range/getRange.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { LockupLinear } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol index d182bbf03..eedcae912 100644 --- a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { LockupLinear } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index 4320a4aac..e81d2a1ab 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol index 2f1d12906..3b1443033 100644 --- a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // solhint-disable max-line-length,no-console,quotes -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { console2 } from "forge-std/src/console2.sol"; import { LibString } from "solady/src/utils/LibString.sol"; diff --git a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol index d193126c9..326d29c31 100644 --- a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; import { WithdrawableAmountOf_Integration_Concrete_Test } from diff --git a/test/integration/concrete/lockup/burn/burn.t.sol b/test/integration/concrete/lockup/burn/burn.t.sol index f73493e41..88d8d52a3 100644 --- a/test/integration/concrete/lockup/burn/burn.t.sol +++ b/test/integration/concrete/lockup/burn/burn.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index 0e69e0b64..6f834ec03 100644 --- a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/integration/concrete/lockup/cancel/cancel.t.sol index b572364c0..38a43306b 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/integration/concrete/lockup/cancel/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol index 820ad51f9..4e469277a 100644 --- a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol +++ b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-asset/getAsset.t.sol b/test/integration/concrete/lockup/get-asset/getAsset.t.sol index b43d23a58..082560891 100644 --- a/test/integration/concrete/lockup/get-asset/getAsset.t.sol +++ b/test/integration/concrete/lockup/get-asset/getAsset.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol b/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol index 97fcfd666..e418e69db 100644 --- a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol +++ b/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol b/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol index f6c6090dc..ed3575642 100644 --- a/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol +++ b/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol index 3e6c06d47..603b3f5b3 100644 --- a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index 70951a7e8..fcfecae3d 100644 --- a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-sender/getSender.t.sol b/test/integration/concrete/lockup/get-sender/getSender.t.sol index f4a008439..713c4f1eb 100644 --- a/test/integration/concrete/lockup/get-sender/getSender.t.sol +++ b/test/integration/concrete/lockup/get-sender/getSender.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol b/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol index 910091a40..e31b8d734 100644 --- a/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol +++ b/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index a7d636336..2558ae6e9 100644 --- a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol index b773ade31..27752ddf2 100644 --- a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/is-cold/isCold.t.sol b/test/integration/concrete/lockup/is-cold/isCold.t.sol index 214512228..84c4bbbbb 100644 --- a/test/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/integration/concrete/lockup/is-cold/isCold.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 6d969a5e8..08cd3b2ad 100644 --- a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/is-stream/isStream.t.sol b/test/integration/concrete/lockup/is-stream/isStream.t.sol index fd44ba2ce..82529686f 100644 --- a/test/integration/concrete/lockup/is-stream/isStream.t.sol +++ b/test/integration/concrete/lockup/is-stream/isStream.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol b/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol index e36599786..e32d1f0f9 100644 --- a/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol +++ b/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/integration/concrete/lockup/is-warm/isWarm.t.sol index 91e2c934d..3ab67548f 100644 --- a/test/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol b/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol index b42cbe56b..444964ec6 100644 --- a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol +++ b/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index df7d7381e..1240e8045 100644 --- a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/renounce/renounce.t.sol b/test/integration/concrete/lockup/renounce/renounce.t.sol index 3f7d871cc..fda715ef4 100644 --- a/test/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/integration/concrete/lockup/renounce/renounce.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol b/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol index 0773070bc..09a585910 100644 --- a/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol +++ b/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol index 1ca11acef..eb7892b66 100644 --- a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/status-of/statusOf.t.sol b/test/integration/concrete/lockup/status-of/statusOf.t.sol index 75775ebe3..d6e2a23a5 100644 --- a/test/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/integration/concrete/lockup/status-of/statusOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index caaa72956..853e600ea 100644 --- a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 648ee00ce..867480479 100644 --- a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol b/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol index 3eea3c362..fb532ea8b 100644 --- a/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol +++ b/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 86bddab4f..6a1d30083 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index 2721c5654..c1bb73538 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index 308fc2b3a..7b469d53d 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index d4c405e84..745a7d5e4 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index 5f38eceb8..7e6c4a099 100644 --- a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol index 4bd60f05e..88e972891 100644 --- a/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "../../Integration.t.sol"; import { NFTDescriptorMock } from "../../../mocks/NFTDescriptorMock.sol"; diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index 4e956be9c..653a8d688 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 16051f57d..30f52ea55 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; diff --git a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol index e22d505e9..e4cf67633 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index 74188c22a..ea4b48345 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/test/integration/fuzz/comptroller/setProtocolFee.t.sol b/test/integration/fuzz/comptroller/setProtocolFee.t.sol index 0db99800c..08afb1b7d 100644 --- a/test/integration/fuzz/comptroller/setProtocolFee.t.sol +++ b/test/integration/fuzz/comptroller/setProtocolFee.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index 5da2393d5..6dcde30a3 100644 --- a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol index aaf2455ab..87a61d646 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol b/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol index cbcf7d2c0..cd54df0c5 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index d8755e6f8..66f2dcca7 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; import { Broker, LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index 196ac96cb..c73d880f5 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index aee569bb8..e44e47485 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/integration/fuzz/lockup-linear/LockupLinear.t.sol index 320ac7f85..eed9b9217 100644 --- a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index c84b7af53..1a0633906 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup-linear/createWithRange.t.sol b/test/integration/fuzz/lockup-linear/createWithRange.t.sol index 3b9cd914b..7b4dbbe56 100644 --- a/test/integration/fuzz/lockup-linear/createWithRange.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithRange.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, UD60x18, ud } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 590400ff4..f738bf2a4 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 07168646e..a76aa21e9 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/integration/fuzz/lockup/cancel.t.sol index d59082cb5..b1b7f59e6 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/integration/fuzz/lockup/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup/cancelMultiple.t.sol b/test/integration/fuzz/lockup/cancelMultiple.t.sol index d9e2b451e..42b61f0c8 100644 --- a/test/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/integration/fuzz/lockup/cancelMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; diff --git a/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol index 88e7c4413..e19422335 100644 --- a/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol +++ b/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { GetWithdrawnAmount_Integration_Shared_Test } from "../../shared/lockup/getWithdrawnAmount.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/refundableAmountOf.t.sol b/test/integration/fuzz/lockup/refundableAmountOf.t.sol index 340352881..92c635e9d 100644 --- a/test/integration/fuzz/lockup/refundableAmountOf.t.sol +++ b/test/integration/fuzz/lockup/refundableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/integration/fuzz/lockup/withdraw.t.sol index 3ef2815c4..6b9c8d3aa 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/integration/fuzz/lockup/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup/withdrawMax.t.sol b/test/integration/fuzz/lockup/withdrawMax.t.sol index 60b631199..d4e4ba06e 100644 --- a/test/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/integration/fuzz/lockup/withdrawMax.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol index 8aef73118..cab8413e5 100644 --- a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { WithdrawMaxAndTransfer_Integration_Shared_Test } from "../../shared/lockup/withdrawMaxAndTransfer.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/integration/fuzz/lockup/withdrawMultiple.t.sol index e26326d4c..307889d33 100644 --- a/test/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 314c81aac..5e1bd327e 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol b/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol index e5c4e51dc..66ae9dcd4 100644 --- a/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol b/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol index a26a14c23..34c08fa11 100644 --- a/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 2a909fa0d..2d90706fd 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/integration/shared/lockup-linear/createWithDurations.t.sol b/test/integration/shared/lockup-linear/createWithDurations.t.sol index e5aac174b..f851e18e1 100644 --- a/test/integration/shared/lockup-linear/createWithDurations.t.sol +++ b/test/integration/shared/lockup-linear/createWithDurations.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/shared/lockup-linear/createWithRange.t.sol b/test/integration/shared/lockup-linear/createWithRange.t.sol index 7a7ff6780..2e7c59223 100644 --- a/test/integration/shared/lockup-linear/createWithRange.t.sol +++ b/test/integration/shared/lockup-linear/createWithRange.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 7974e50d6..8fd00072c 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/integration/shared/lockup/cancel.t.sol b/test/integration/shared/lockup/cancel.t.sol index eba14f6ac..7f6427184 100644 --- a/test/integration/shared/lockup/cancel.t.sol +++ b/test/integration/shared/lockup/cancel.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/cancelMultiple.t.sol b/test/integration/shared/lockup/cancelMultiple.t.sol index f5f366c8b..79f62047f 100644 --- a/test/integration/shared/lockup/cancelMultiple.t.sol +++ b/test/integration/shared/lockup/cancelMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/getWithdrawnAmount.t.sol b/test/integration/shared/lockup/getWithdrawnAmount.t.sol index b88b483d7..35bd18a30 100644 --- a/test/integration/shared/lockup/getWithdrawnAmount.t.sol +++ b/test/integration/shared/lockup/getWithdrawnAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/streamedAmountOf.t.sol b/test/integration/shared/lockup/streamedAmountOf.t.sol index da3f03619..fd9673265 100644 --- a/test/integration/shared/lockup/streamedAmountOf.t.sol +++ b/test/integration/shared/lockup/streamedAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 9b5d21454..300b89f61 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/withdrawMax.t.sol b/test/integration/shared/lockup/withdrawMax.t.sol index a60582981..f2b083058 100644 --- a/test/integration/shared/lockup/withdrawMax.t.sol +++ b/test/integration/shared/lockup/withdrawMax.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol index 5f6fcf64f..f332e3dde 100644 --- a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/withdrawMultiple.t.sol b/test/integration/shared/lockup/withdrawMultiple.t.sol index 2896f77c7..a20815ae2 100644 --- a/test/integration/shared/lockup/withdrawMultiple.t.sol +++ b/test/integration/shared/lockup/withdrawMultiple.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/integration/shared/lockup/withdrawableAmountOf.t.sol b/test/integration/shared/lockup/withdrawableAmountOf.t.sol index 609a9a2dd..9abf213aa 100644 --- a/test/integration/shared/lockup/withdrawableAmountOf.t.sol +++ b/test/integration/shared/lockup/withdrawableAmountOf.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; diff --git a/test/invariant/Invariant.t.sol b/test/invariant/Invariant.t.sol index 8e563b6c5..f94d792bb 100644 --- a/test/invariant/Invariant.t.sol +++ b/test/invariant/Invariant.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { StdInvariant } from "forge-std/src/StdInvariant.sol"; diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index f6b4c7922..ffe71ea59 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index 2fd242720..31e3c0a57 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index b0af03760..adb8b5db2 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; diff --git a/test/invariant/handlers/BaseHandler.sol b/test/invariant/handlers/BaseHandler.sol index 75523ea07..7719b88e4 100644 --- a/test/invariant/handlers/BaseHandler.sol +++ b/test/invariant/handlers/BaseHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Vm } from "@prb/test/src/PRBTest.sol"; diff --git a/test/invariant/handlers/ComptrollerHandler.sol b/test/invariant/handlers/ComptrollerHandler.sol index 8c374a788..71575e49a 100644 --- a/test/invariant/handlers/ComptrollerHandler.sol +++ b/test/invariant/handlers/ComptrollerHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, UNIT } from "@prb/math/src/UD60x18.sol"; diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 025cf43fd..b101c2873 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/invariant/handlers/LockupDynamicHandler.sol b/test/invariant/handlers/LockupDynamicHandler.sol index 9a33711a3..b18945add 100644 --- a/test/invariant/handlers/LockupDynamicHandler.sol +++ b/test/invariant/handlers/LockupDynamicHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index 1a93ffc24..53b4bdcc0 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index a6c2c82d8..af048de0a 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/invariant/handlers/LockupLinearHandler.sol b/test/invariant/handlers/LockupLinearHandler.sol index 0c5bca009..83bca10e4 100644 --- a/test/invariant/handlers/LockupLinearHandler.sol +++ b/test/invariant/handlers/LockupLinearHandler.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/invariant/stores/LockupStore.sol b/test/invariant/stores/LockupStore.sol index 1106cf0f6..f74d5d0c7 100644 --- a/test/invariant/stores/LockupStore.sol +++ b/test/invariant/stores/LockupStore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/invariant/stores/TimestampStore.sol b/test/invariant/stores/TimestampStore.sol index d214e0726..573b039d7 100644 --- a/test/invariant/stores/TimestampStore.sol +++ b/test/invariant/stores/TimestampStore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; /// @dev Because Foundry does not commit the state changes between invariant runs, we need to /// save the current timestamp in a contract with persistent storage. diff --git a/test/mocks/AdminableMock.sol b/test/mocks/AdminableMock.sol index 3b358a5ac..0ea10b4b6 100644 --- a/test/mocks/AdminableMock.sol +++ b/test/mocks/AdminableMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { Adminable } from "../../src/abstracts/Adminable.sol"; import { IAdminable } from "../../src/interfaces/IAdminable.sol"; diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index b9b22f1a4..6d93fb7d8 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/test/mocks/Noop.sol b/test/mocks/Noop.sol index eb9ce1363..9b46e3a14 100644 --- a/test/mocks/Noop.sol +++ b/test/mocks/Noop.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; /// @dev This contract does nothing (no-op = no operation). contract Noop { } diff --git a/test/mocks/erc20/ERC20Bytes32.sol b/test/mocks/erc20/ERC20Bytes32.sol index fc2480d33..50b065903 100644 --- a/test/mocks/erc20/ERC20Bytes32.sol +++ b/test/mocks/erc20/ERC20Bytes32.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; contract ERC20Bytes32 { function symbol() external pure returns (bytes32) { diff --git a/test/mocks/erc20/ERC20MissingReturn.sol b/test/mocks/erc20/ERC20MissingReturn.sol index 3e4d47143..0f9d548e7 100644 --- a/test/mocks/erc20/ERC20MissingReturn.sol +++ b/test/mocks/erc20/ERC20MissingReturn.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; /// @notice An implementation of ERC-20 that does not return a boolean in {transfer} and {transferFrom}. /// @dev See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca/. diff --git a/test/mocks/hooks/GoodRecipient.sol b/test/mocks/hooks/GoodRecipient.sol index 2a72f2eaa..a2601e679 100644 --- a/test/mocks/hooks/GoodRecipient.sol +++ b/test/mocks/hooks/GoodRecipient.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/mocks/hooks/GoodSender.sol b/test/mocks/hooks/GoodSender.sol index eb8f09e79..564d3cc07 100644 --- a/test/mocks/hooks/GoodSender.sol +++ b/test/mocks/hooks/GoodSender.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; diff --git a/test/mocks/hooks/ReentrantRecipient.sol b/test/mocks/hooks/ReentrantRecipient.sol index 551e6ed6e..567b486e9 100644 --- a/test/mocks/hooks/ReentrantRecipient.sol +++ b/test/mocks/hooks/ReentrantRecipient.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/mocks/hooks/ReentrantSender.sol b/test/mocks/hooks/ReentrantSender.sol index 4eaf833d4..ab10c75eb 100644 --- a/test/mocks/hooks/ReentrantSender.sol +++ b/test/mocks/hooks/ReentrantSender.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; diff --git a/test/mocks/hooks/RevertingRecipient.sol b/test/mocks/hooks/RevertingRecipient.sol index d9255d12e..339ce281a 100644 --- a/test/mocks/hooks/RevertingRecipient.sol +++ b/test/mocks/hooks/RevertingRecipient.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; diff --git a/test/mocks/hooks/RevertingSender.sol b/test/mocks/hooks/RevertingSender.sol index 3af539484..98f47ce97 100644 --- a/test/mocks/hooks/RevertingSender.sol +++ b/test/mocks/hooks/RevertingSender.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; diff --git a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol b/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol index 16bb5e4de..c8b27a5d8 100644 --- a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol +++ b/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/unit/concrete/comptroller/Comptroller.t.sol b/test/unit/concrete/comptroller/Comptroller.t.sol index 635946627..e3899b8b4 100644 --- a/test/unit/concrete/comptroller/Comptroller.t.sol +++ b/test/unit/concrete/comptroller/Comptroller.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SablierV2Comptroller } from "../../../../src/SablierV2Comptroller.sol"; diff --git a/test/unit/concrete/comptroller/constructor.t.sol b/test/unit/concrete/comptroller/constructor.t.sol index 6c03fe5f5..80d16c1d9 100644 --- a/test/unit/concrete/comptroller/constructor.t.sol +++ b/test/unit/concrete/comptroller/constructor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SablierV2Comptroller } from "src/SablierV2Comptroller.sol"; diff --git a/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol index 8fe60913d..f2c26b5ee 100644 --- a/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SablierV2NFTDescriptor } from "src/SablierV2NFTDescriptor.sol"; diff --git a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol b/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol index 6a9d927ca..b01b1ba38 100644 --- a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol +++ b/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/libraries/SVGElements.sol"; diff --git a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol b/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol index 886735e00..8d5cf0a2b 100644 --- a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol +++ b/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/libraries/SVGElements.sol"; diff --git a/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol b/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol index a8c73c30b..ec70b8394 100644 --- a/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol +++ b/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol b/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol index a8b642e71..e30d6bdba 100644 --- a/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol +++ b/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/generateAttributes.t.sol b/test/unit/concrete/nft-descriptor/generateAttributes.t.sol index 68b490107..c0b005706 100644 --- a/test/unit/concrete/nft-descriptor/generateAttributes.t.sol +++ b/test/unit/concrete/nft-descriptor/generateAttributes.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // solhint-disable max-line-length,quotes -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/unit/concrete/nft-descriptor/generateDescription.t.sol index aacded97a..8a295e59e 100644 --- a/test/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/test/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // solhint-disable max-line-length,quotes -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/generateName.t.sol b/test/unit/concrete/nft-descriptor/generateName.t.sol index 4f1d98231..13c6631d4 100644 --- a/test/unit/concrete/nft-descriptor/generateName.t.sol +++ b/test/unit/concrete/nft-descriptor/generateName.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/unit/concrete/nft-descriptor/generateSVG.t.sol index 8230c5970..750124ed0 100644 --- a/test/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: UNLICENSED // solhint-disable max-line-length -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTSVG } from "src/libraries/NFTSVG.sol"; import { SVGElements } from "src/libraries/SVGElements.sol"; diff --git a/test/unit/concrete/nft-descriptor/hourglass.t.sol b/test/unit/concrete/nft-descriptor/hourglass.t.sol index 4c67580de..ff331479c 100644 --- a/test/unit/concrete/nft-descriptor/hourglass.t.sol +++ b/test/unit/concrete/nft-descriptor/hourglass.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol b/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol index 9f5797882..09c396f11 100644 --- a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/libraries/SVGElements.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol b/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol index ee248d1cd..4936545a0 100644 --- a/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol b/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol index f60682af6..15a676db1 100644 --- a/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol b/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol index e7404f7d2..62dbe04f9 100644 --- a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/types/DataTypes.sol"; diff --git a/test/unit/fuzz/transferAdmin.t.sol b/test/unit/fuzz/transferAdmin.t.sol index b762991fc..9b44c3be2 100644 --- a/test/unit/fuzz/transferAdmin.t.sol +++ b/test/unit/fuzz/transferAdmin.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; diff --git a/test/unit/shared/Adminable.t.sol b/test/unit/shared/Adminable.t.sol index a2e3b6ae9..bb8fcdd2d 100644 --- a/test/unit/shared/Adminable.t.sol +++ b/test/unit/shared/Adminable.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { Base_Test } from "../../Base.t.sol"; import { AdminableMock } from "../../mocks/AdminableMock.sol"; diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index f4f86cd5c..86b14ef04 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index 1a867d7bb..f1f3ceae7 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uint40.sol"; diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 4827bc5b3..b65cfc8eb 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 85e20bec7..ab155e8cd 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD2x18, ud2x18 } from "@prb/math/src/UD2x18.sol"; diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index 6891b70cf..063196565 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { StdCheats } from "forge-std/src/StdCheats.sol"; diff --git a/test/utils/Events.sol b/test/utils/Events.sol index da24266d4..13b51883a 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index b9a8f6a26..a42184ebd 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { UD60x18, ud, uUNIT } from "@prb/math/src/UD60x18.sol"; diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 0d9780746..11069a5c4 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 // solhint-disable max-line-length,no-inline-assembly,reason-string -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 998f48a5c..15d2768ee 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.19 <0.9.0; +pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; diff --git a/test/utils/Types.sol b/test/utils/Types.sol index 25997cd07..2ba8fdb1c 100644 --- a/test/utils/Types.sol +++ b/test/utils/Types.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; struct Users { // Default admin for all Sablier V2 contracts. diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index f2e483e6e..86db15427 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.19; +pragma solidity >=0.8.22; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol"; From 2e1c95997d7e2ce5a606d9f07305c519274b26ef Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 6 Jan 2024 21:13:03 +0530 Subject: [PATCH 034/132] refactor: consistency in calldata related struct parameters --- script/Init.s.sol | 8 ++--- src/SablierV2LockupDynamic.sol | 10 +++--- src/SablierV2LockupLinear.sol | 8 ++--- src/types/DataTypes.sol | 26 +++++++------- test/fork/LockupDynamic.t.sol | 20 +++++------ test/fork/LockupLinear.t.sol | 18 +++++----- .../lockup-dynamic/createWithMilestones.t.sol | 10 +++--- .../fuzz/lockup-linear/createWithRange.t.sol | 10 +++--- test/utils/Defaults.sol | 34 +++++++++---------- 9 files changed, 72 insertions(+), 72 deletions(-) diff --git a/script/Init.s.sol b/script/Init.s.sol index 506dbc05b..4186ac3e0 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -83,14 +83,14 @@ contract Init is BaseScript { segments[1] = LockupDynamic.SegmentWithDelta({ amount: 7500e18, exponent: ud2x18(0.5e18), delta: 1 weeks }); lockupDynamic.createWithDeltas( LockupDynamic.CreateWithDeltas({ + sender: sender, + recipient: recipient, + totalAmount: 10_000e18, asset: asset, - broker: Broker(address(0), ud60x18(0)), cancelable: true, transferable: true, - recipient: recipient, - sender: sender, segments: segments, - totalAmount: 10_000e18 + broker: Broker(address(0), ud60x18(0)) }) ); } diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 730c30074..03fc8c8d5 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -279,15 +279,15 @@ contract SablierV2LockupDynamic is // Checks, Effects and Interactions: create the stream. streamId = _createWithMilestones( LockupDynamic.CreateWithMilestones({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, asset: params.asset, - broker: params.broker, cancelable: params.cancelable, transferable: params.transferable, - recipient: params.recipient, - segments: segments, - sender: params.sender, startTime: uint40(block.timestamp), - totalAmount: params.totalAmount + segments: segments, + broker: params.broker }) ); } diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 5a5ad8adb..56fe191c9 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -270,14 +270,14 @@ contract SablierV2LockupLinear is // Checks, Effects and Interactions: create the stream. streamId = _createWithRange( LockupLinear.CreateWithRange({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, asset: params.asset, - broker: params.broker, cancelable: params.cancelable, transferable: params.transferable, range: range, - recipient: params.recipient, - sender: params.sender, - totalAmount: params.totalAmount + broker: params.broker }) ); } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 1120d6e8f..ce6366ed5 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -79,45 +79,45 @@ library LockupDynamic { /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the - /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. /// @param segments Segments with deltas used to compose the custom streaming curve. Milestones are calculated by /// starting from `block.timestamp` and adding each delta to the previous milestone. + /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDeltas { address sender; - bool cancelable; - bool transferable; address recipient; uint128 totalAmount; IERC20 asset; - Broker broker; + bool cancelable; + bool transferable; SegmentWithDelta[] segments; + Broker broker; } /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithMilestones} /// function. /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. - /// @param startTime The Unix timestamp indicating the stream's start. - /// @param cancelable Indicates if the stream is cancelable. - /// @param transferable Indicates if the stream NFT is transferable. /// @param recipient The address receiving the assets. /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential /// fees, all denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param cancelable Indicates if the stream is cancelable. + /// @param transferable Indicates if the stream NFT is transferable. + /// @param startTime The Unix timestamp indicating the stream's start. + /// @param segments Segments used to compose the custom streaming curve. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. - /// @param segments Segments used to compose the custom streaming curve. struct CreateWithMilestones { address sender; - uint40 startTime; - bool cancelable; - bool transferable; address recipient; uint128 totalAmount; IERC20 asset; - Broker broker; + bool cancelable; + bool transferable; + uint40 startTime; Segment[] segments; + Broker broker; } /// @notice Struct encapsulating the time range. diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 9219af5e7..ea1f40f5a 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -34,15 +34,15 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { //////////////////////////////////////////////////////////////////////////*/ struct Params { - Broker broker; - UD60x18 protocolFee; - address recipient; address sender; + address recipient; + uint128 withdrawAmount; + bool transferable; + UD60x18 protocolFee; uint40 startTime; uint40 warpTimestamp; LockupDynamic.Segment[] segments; - uint128 withdrawAmount; - bool transferable; + Broker broker; } struct Vars { @@ -179,15 +179,15 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { // Create the stream. lockupDynamic.createWithMilestones( LockupDynamic.CreateWithMilestones({ + sender: params.sender, + recipient: params.recipient, + totalAmount: vars.totalAmount, asset: ASSET, - broker: params.broker, cancelable: true, transferable: params.transferable, - recipient: params.recipient, - segments: params.segments, - sender: params.sender, startTime: params.startTime, - totalAmount: vars.totalAmount + segments: params.segments, + broker: params.broker }) ); diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index 0ed6ca9f2..7207590fd 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -34,15 +34,15 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { //////////////////////////////////////////////////////////////////////////*/ struct Params { - Broker broker; - UD60x18 protocolFee; - LockupLinear.Range range; - address recipient; address sender; + address recipient; uint128 totalAmount; - uint40 warpTimestamp; uint128 withdrawAmount; bool transferable; + UD60x18 protocolFee; + uint40 warpTimestamp; + LockupLinear.Range range; + Broker broker; } struct Vars { @@ -181,14 +181,14 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Create the stream. lockupLinear.createWithRange( LockupLinear.CreateWithRange({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, asset: ASSET, - broker: params.broker, cancelable: true, transferable: params.transferable, range: params.range, - recipient: params.recipient, - sender: params.sender, - totalAmount: params.totalAmount + broker: params.broker }) ); diff --git a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol b/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol index cd54df0c5..6db69943c 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol @@ -287,15 +287,15 @@ contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is // Create the stream. lockupDynamic.createWithMilestones( LockupDynamic.CreateWithMilestones({ + sender: params.sender, + recipient: params.recipient, + totalAmount: vars.totalAmount, asset: dai, - broker: params.broker, cancelable: params.cancelable, transferable: params.transferable, - recipient: params.recipient, - segments: params.segments, - sender: params.sender, startTime: params.startTime, - totalAmount: vars.totalAmount + segments: params.segments, + broker: params.broker }) ); diff --git a/test/integration/fuzz/lockup-linear/createWithRange.t.sol b/test/integration/fuzz/lockup-linear/createWithRange.t.sol index 7b4dbbe56..e82fb3123 100644 --- a/test/integration/fuzz/lockup-linear/createWithRange.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithRange.t.sol @@ -198,14 +198,14 @@ contract CreateWithRange_LockupLinear_Integration_Fuzz_Test is // Create the stream. lockupLinear.createWithRange( LockupLinear.CreateWithRange({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, asset: dai, - broker: params.broker, cancelable: params.cancelable, - range: params.range, - recipient: params.recipient, transferable: params.transferable, - sender: params.sender, - totalAmount: params.totalAmount + range: params.range, + broker: params.broker }) ); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index ab155e8cd..244bfbff0 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -183,54 +183,54 @@ contract Defaults is Constants { function createWithDeltas() public view returns (LockupDynamic.CreateWithDeltas memory) { return LockupDynamic.CreateWithDeltas({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, asset: asset, - broker: broker(), cancelable: true, transferable: true, - recipient: users.recipient, segments: segmentsWithDeltas(), - sender: users.sender, - totalAmount: TOTAL_AMOUNT + broker: broker() }); } function createWithDurations() public view returns (LockupLinear.CreateWithDurations memory) { return LockupLinear.CreateWithDurations({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, asset: asset, - broker: broker(), cancelable: true, transferable: true, durations: durations(), - recipient: users.recipient, - sender: users.sender, - totalAmount: TOTAL_AMOUNT + broker: broker() }); } function createWithMilestones() public view returns (LockupDynamic.CreateWithMilestones memory) { return LockupDynamic.CreateWithMilestones({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, asset: asset, - broker: broker(), cancelable: true, transferable: true, - recipient: users.recipient, - segments: segments(), - sender: users.sender, startTime: START_TIME, - totalAmount: TOTAL_AMOUNT + segments: segments(), + broker: broker() }); } function createWithRange() public view returns (LockupLinear.CreateWithRange memory) { return LockupLinear.CreateWithRange({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, asset: asset, - broker: broker(), cancelable: true, transferable: true, range: lockupLinearRange(), - recipient: users.recipient, - sender: users.sender, - totalAmount: TOTAL_AMOUNT + broker: broker() }); } } From eb411e26e585daf803453bb108ec087707411907 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:42:37 +0200 Subject: [PATCH 035/132] refactor: make nftDescriptor public (#796) test: nftDescriptor in constructor --- src/abstracts/SablierV2Lockup.sol | 16 ++++++---------- src/interfaces/ISablierV2Lockup.sol | 3 +++ .../concrete/lockup-dynamic/constructor.t.sol | 4 ++++ .../concrete/lockup-linear/constructor.t.sol | 4 ++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 1a04271a3..158d12aea 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -29,12 +29,8 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup uint256 public override nextStreamId; - /*////////////////////////////////////////////////////////////////////////// - INTERNAL STORAGE - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Contract that generates the non-fungible token URI. - ISablierV2NFTDescriptor internal _nftDescriptor; + /// @inheritdoc ISablierV2Lockup + ISablierV2NFTDescriptor public override nftDescriptor; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -50,7 +46,7 @@ abstract contract SablierV2Lockup is ) SablierV2Base(initialAdmin, initialComptroller) { - _nftDescriptor = initialNFTDescriptor; + nftDescriptor = initialNFTDescriptor; } /*////////////////////////////////////////////////////////////////////////// @@ -111,7 +107,7 @@ abstract contract SablierV2Lockup is _requireMinted({ tokenId: streamId }); // Generate the URI describing the stream NFT. - uri = _nftDescriptor.tokenURI({ sablier: this, streamId: streamId }); + uri = nftDescriptor.tokenURI({ sablier: this, streamId: streamId }); } /// @inheritdoc ISablierV2Lockup @@ -215,8 +211,8 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function setNFTDescriptor(ISablierV2NFTDescriptor newNFTDescriptor) external override onlyAdmin { // Effects: set the NFT descriptor. - ISablierV2NFTDescriptor oldNftDescriptor = _nftDescriptor; - _nftDescriptor = newNFTDescriptor; + ISablierV2NFTDescriptor oldNftDescriptor = nftDescriptor; + nftDescriptor = newNFTDescriptor; // Log the change of the NFT descriptor. emit ISablierV2Lockup.SetNFTDescriptor({ diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 90271b846..b21eb3e0e 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -134,6 +134,9 @@ interface ISablierV2Lockup is /// @notice Counter for stream ids, used in the create functions. function nextStreamId() external view returns (uint256); + /// @notice Contract that generates the non-fungible token URI. + function nftDescriptor() external view returns (ISablierV2NFTDescriptor); + /// @notice Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units /// of the asset's decimals. /// @dev Reverts if `streamId` references a null stream. diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index f27859db7..97d32973d 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -33,6 +33,10 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); + address actualNFTDescriptor = address(constructedLockupDynamic.nftDescriptor()); + address expectedNFTDescriptor = address(nftDescriptor); + assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); + // {SablierV2LockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index 9feb34691..d5a8ba385 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -31,5 +31,9 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte uint256 actualStreamId = constructedLockupLinear.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); + + address actualNFTDescriptor = address(constructedLockupLinear.nftDescriptor()); + address expectedNFTDescriptor = address(nftDescriptor); + assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); } } From 30e670fad0e5e8a7ec1e723d51bb7772ea0fcf28 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Sun, 21 Jan 2024 22:31:13 +0200 Subject: [PATCH 036/132] chore: use pragma solidity >=0.8.22 in Core3 scripts --- script/DeployCore3.s.sol | 2 +- script/DeployDeterministicCore3.s.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol index 5d71594c6..5d9d67990 100644 --- a/script/DeployCore3.s.sol +++ b/script/DeployCore3.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.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol index 3335c3a97..a96d8c733 100644 --- a/script/DeployDeterministicCore3.s.sol +++ b/script/DeployDeterministicCore3.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.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; From 7106c79cc16765df8d95afb0d9688179f365e1c7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 24 Jan 2024 02:18:12 +0530 Subject: [PATCH 037/132] feat: `withdraw` callable by any account (#785) * feat: `withdraw` function callable by any account feat: `withdrawMultiple` calls withdraw on streams recipient test: fuzz test for with when the caller is an unknown address refactor: rename custom error chore: improve explanatory comments test: undo authorized test branches test: say uknown address instead of public caller test: make withdraw fuzz test more minimalist * refactor: withdraw related notes (#791) * docs: improve writing in NatSpec comments refactor: reorder errors test: improve names for functions and variables * refactor: withdraw tree * refactor: order of checks in "withdraw" test: polish withdraw tree and tests --------- Co-authored-by: Paul Razvan Berg --- src/abstracts/SablierV2Lockup.sol | 27 +- src/interfaces/ISablierV2Lockup.sol | 17 +- src/interfaces/hooks/ISablierV2Recipient.sol | 2 +- src/interfaces/hooks/ISablierV2Sender.sol | 2 +- src/libraries/Errors.sol | 6 +- .../withdraw-multiple/withdrawMultiple.t.sol | 129 +-------- .../withdraw-multiple/withdrawMultiple.tree | 32 +-- .../concrete/lockup/withdraw/withdraw.t.sol | 248 +++++++++++------- .../concrete/lockup/withdraw/withdraw.tree | 162 ++++++------ .../fuzz/lockup-dynamic/withdraw.t.sol | 3 +- test/integration/fuzz/lockup/withdraw.t.sol | 43 ++- .../fuzz/lockup/withdrawMultiple.t.sol | 27 +- test/integration/shared/lockup/withdraw.t.sol | 10 +- 13 files changed, 342 insertions(+), 366 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 158d12aea..d75a1f87d 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -241,21 +241,6 @@ 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 && !_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 && to != recipient) { - revert Errors.SablierV2Lockup_InvalidSenderWithdrawal(streamId, msg.sender, to); - } - // Checks: the withdrawal address is not zero. if (to == address(0)) { revert Errors.SablierV2Lockup_WithdrawToZeroAddress(); @@ -266,6 +251,15 @@ abstract contract SablierV2Lockup is revert Errors.SablierV2Lockup_WithdrawAmountZero(streamId); } + // Retrieve the recipient from storage. + address recipient = _ownerOf(streamId); + + // Checks: if `msg.sender` is neither the stream's recipient nor an approved third party, the withdrawal address + // must be the recipient. + if (to != recipient && !_isCallerStreamRecipientOrApproved(streamId)) { + revert Errors.SablierV2Lockup_WithdrawalAddressNotRecipient(streamId, msg.sender, to); + } + // Checks: the withdraw amount is not greater than the withdrawable amount. uint128 withdrawableAmount = _withdrawableAmountOf(streamId); if (amount > withdrawableAmount) { @@ -337,7 +331,6 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function withdrawMultiple( uint256[] calldata streamIds, - address to, uint128[] calldata amounts ) external @@ -354,7 +347,7 @@ abstract contract SablierV2Lockup is // Iterate over the provided array of stream ids and withdraw from each stream. for (uint256 i = 0; i < streamIdsCount; ++i) { // Checks, Effects and Interactions: check the parameters and make the withdrawal. - withdraw(streamIds[i], to, amounts[i]); + withdraw({ streamId: streamIds[i], to: _ownerOf(streamIds[i]), amount: amounts[i] }); } } diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index b21eb3e0e..e129860e8 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -245,16 +245,15 @@ interface ISablierV2Lockup is /// @dev Emits a {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} event. /// /// Notes: - /// - This function attempts to invoke a hook on the stream's recipient, provided that the recipient is a contract - /// and `msg.sender` is either the sender or an approved operator. + /// - This function attempts to call a hook on the recipient of the stream, unless `msg.sender` is the recipient. + /// - This function attempts to call a hook on the sender of the stream, unless `msg.sender` is the sender. /// /// Requirements: /// - Must not be delegate called. /// - `streamId` must not reference a null or depleted stream. - /// - `msg.sender` must be the stream's sender, the stream's recipient or an approved third party. - /// - `to` must be the recipient if `msg.sender` is the stream's sender. /// - `to` must not be the zero address. /// - `amount` must be greater than zero and must not exceed the withdrawable amount. + /// - `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. /// /// @param streamId The id of the stream to withdraw from. /// @param to The address receiving the withdrawn assets. @@ -293,19 +292,21 @@ interface ISablierV2Lockup is /// @param newRecipient The address of the new owner of the stream NFT. function withdrawMaxAndTransfer(uint256 streamId, address newRecipient) external; - /// @notice Withdraws assets from streams to the provided address `to`. + /// @notice Withdraws assets from streams to the recipient of each stream. /// /// @dev Emits multiple {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} events. /// /// Notes: /// - This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. + /// - This function attempts to call a hook on the sender of each stream, unless `msg.sender` is the sender. /// /// Requirements: - /// - All requirements from {withdraw} must be met for each stream. + /// - Must not be delegate called. /// - There must be an equal number of `streamIds` and `amounts`. + /// - Each stream id in the array must not reference a null or depleted stream. + /// - Each amount in the array must be greater than zero and must not exceed the withdrawable amount. /// /// @param streamIds The ids of the streams to withdraw from. - /// @param to The address receiving the withdrawn assets. /// @param amounts The amounts to withdraw, denoted in units of the asset's decimals. - function withdrawMultiple(uint256[] calldata streamIds, address to, uint128[] calldata amounts) external; + function withdrawMultiple(uint256[] calldata streamIds, uint128[] calldata amounts) external; } diff --git a/src/interfaces/hooks/ISablierV2Recipient.sol b/src/interfaces/hooks/ISablierV2Recipient.sol index d6e029af6..128d3b958 100644 --- a/src/interfaces/hooks/ISablierV2Recipient.sol +++ b/src/interfaces/hooks/ISablierV2Recipient.sol @@ -33,7 +33,7 @@ interface ISablierV2Recipient { /// @param streamId The id of the renounced stream. function onLockupStreamRenounced(uint256 streamId) external; - /// @notice Responds to withdrawals triggered by either the stream's sender or an approved third party. + /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. /// /// @dev Notes: /// - This function may revert, but the Sablier contract will ignore the revert. diff --git a/src/interfaces/hooks/ISablierV2Sender.sol b/src/interfaces/hooks/ISablierV2Sender.sol index 632e13065..904380460 100644 --- a/src/interfaces/hooks/ISablierV2Sender.sol +++ b/src/interfaces/hooks/ISablierV2Sender.sol @@ -6,7 +6,7 @@ pragma solidity >=0.8.22; /// @dev Implementation of this interface is optional. If a sender contract doesn't implement this /// interface or implements it partially, function execution will not revert. interface ISablierV2Sender { - /// @notice Responds to withdrawals triggered by either the stream's recipient or an approved third party. + /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. /// /// @dev Notes: /// - This function may revert, but the Sablier contract will ignore the revert. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index bf9548520..d410a9255 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -38,9 +38,6 @@ library Errors { /// @notice Thrown when trying to create a stream with an end time not in the future. error SablierV2Lockup_EndTimeNotInTheFuture(uint40 currentTime, uint40 endTime); - /// @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); @@ -71,6 +68,9 @@ library Errors { /// @notice Thrown when `msg.sender` lacks authorization to perform an action. error SablierV2Lockup_Unauthorized(uint256 streamId, address caller); + /// @notice Thrown when trying to withdraw to an address other than the recipient's. + error SablierV2Lockup_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); + /// @notice Thrown when trying to withdraw zero assets from a stream. error SablierV2Lockup_WithdrawAmountZero(uint256 streamId); diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index 7b469d53d..915b4c709 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -19,8 +19,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = - abi.encodeCall(ISablierV2Lockup.withdrawMultiple, (testStreamIds, users.recipient, testAmounts)); + bytes memory callData = abi.encodeCall(ISablierV2Lockup.withdrawMultiple, (testStreamIds, testAmounts)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -33,7 +32,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is Errors.SablierV2Lockup_WithdrawArrayCountsNotEqual.selector, streamIds.length, amounts.length ) ); - lockup.withdrawMultiple({ streamIds: streamIds, to: users.recipient, amounts: amounts }); + lockup.withdrawMultiple(streamIds, amounts); } modifier whenArrayCountsAreEqual() { @@ -43,7 +42,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is function test_WithdrawMultiple_ArrayCountsZero() external whenNotDelegateCalled whenArrayCountsAreEqual { uint256[] memory streamIds = new uint256[](0); uint128[] memory amounts = new uint128[](0); - lockup.withdrawMultiple({ streamIds: streamIds, to: users.recipient, amounts: amounts }); + lockup.withdrawMultiple(streamIds, amounts); } modifier whenArrayCountsNotZero() { @@ -61,7 +60,6 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); lockup.withdrawMultiple({ streamIds: Solarray.uint256s(nullStreamId), - to: users.recipient, amounts: Solarray.uint128s(withdrawAmount) }); } @@ -82,7 +80,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); // Withdraw from multiple streams. - lockup.withdrawMultiple({ streamIds: streamIds, to: users.recipient, amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: streamIds, amounts: testAmounts }); } function test_RevertGiven_AllStatusesDepleted() @@ -105,7 +103,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); // Withdraw from multiple streams. - lockup.withdrawMultiple({ streamIds: streamIds, to: users.recipient, amounts: amounts }); + lockup.withdrawMultiple(streamIds, amounts); } function test_RevertGiven_SomeStatusesDepleted() @@ -125,113 +123,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); // Withdraw from multiple streams. - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: testAmounts }); - } - - function test_RevertWhen_CallerUnauthorizedAllStreams_MaliciousThirdParty() - external - whenNotDelegateCalled - whenArrayCountsAreEqual - whenArrayCountsNotZero - givenNoNull - givenNoDepletedStream - whenCallerUnauthorized - { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.eve) - ); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: testAmounts }); - } - - function test_RevertWhen_CallerUnauthorizedAllStreams_FormerRecipient() - external - whenNotDelegateCalled - whenArrayCountsAreEqual - whenArrayCountsNotZero - givenNoNull - givenNoDepletedStream - whenCallerUnauthorized - { - // Transfer all streams to Alice. - changePrank({ msgSender: users.recipient }); - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: testStreamIds[0] }); - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: testStreamIds[1] }); - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: testStreamIds[2] }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) - ); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: testAmounts }); - } - - function test_RevertWhen_CallerUnauthorizedSomeStreams_MaliciousThirdParty() - external - whenNotDelegateCalled - whenArrayCountsAreEqual - whenArrayCountsNotZero - givenNoNull - givenNoDepletedStream - whenCallerUnauthorized - { - // Create a stream with Eve as the stream's recipient. - uint256 eveStreamId = createDefaultStreamWithRecipient(users.eve); - - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Run the test. - uint256[] memory streamIds = Solarray.uint256s(eveStreamId, testStreamIds[0], testStreamIds[1]); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.eve) - ); - lockup.withdrawMultiple({ streamIds: streamIds, to: users.recipient, amounts: testAmounts }); - } - - function test_RevertWhen_CallerUnauthorizedSomeStreams_FormerRecipient() - external - whenNotDelegateCalled - whenArrayCountsAreEqual - whenArrayCountsNotZero - givenNoNull - givenNoDepletedStream - whenCallerUnauthorized - { - // Transfer one of the streams to Eve. - changePrank({ msgSender: users.recipient }); - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: testStreamIds[0] }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) - ); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: testAmounts }); - } - - function test_RevertWhen_ToZeroAddress() - external - whenNotDelegateCalled - whenArrayCountsAreEqual - whenArrayCountsNotZero - givenNoNull - givenNoDepletedStream - whenCallerAuthorizedAllStreams - { - if (caller == users.sender) { - return; - } - vm.expectRevert(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: address(0), amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: testAmounts }); } function test_RevertWhen_SomeAmountsZero() @@ -241,7 +133,6 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenArrayCountsNotZero givenNoNull givenNoDepletedStream - whenCallerAuthorizedAllStreams whenToNonZeroAddress { // Simulate the passage of time. @@ -250,7 +141,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is // Run the test. uint128[] memory amounts = Solarray.uint128s(defaults.WITHDRAW_AMOUNT(), 0, 0); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, testStreamIds[1])); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: amounts }); + lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); } function test_RevertWhen_SomeAmountsOverdraw() @@ -260,7 +151,6 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenArrayCountsNotZero givenNoNull givenNoDepletedStream - whenCallerAuthorizedAllStreams whenToNonZeroAddress whenNoAmountZero { @@ -275,7 +165,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is Errors.SablierV2Lockup_Overdraw.selector, testStreamIds[2], MAX_UINT128, withdrawableAmount ) ); - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: amounts }); + lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); } function test_WithdrawMultiple() @@ -285,7 +175,6 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenArrayCountsNotZero givenNoNull givenNoDepletedStream - whenCallerAuthorizedAllStreams whenToNonZeroAddress whenNoAmountZero whenNoAmountOverdraws @@ -329,7 +218,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is }); // Make the withdrawals. - lockup.withdrawMultiple({ streamIds: testStreamIds, to: users.recipient, amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: testAmounts }); // Assert that the statuses have been updated. assertEq(lockup.statusOf(testStreamIds[0]), Lockup.Status.STREAMING, "status0"); diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree index 52ca2f9e7..6759b6aa2 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree @@ -18,27 +18,13 @@ withdrawMultiple.t.sol ├── given some streams' statuses are "DEPLETED" │ └── it should revert └── given no stream's status is "DEPLETED" - ├── when the caller is unauthorized for all streams - │ ├── when the caller is a malicious third party - │ │ └── it should revert - │ └── when the caller is a former recipient - │ └── it should revert - ├── when the caller is unauthorized for some streams - │ ├── when the caller is a malicious third party - │ │ └── it should revert - │ └── when the caller is a former recipient - │ └── it should revert - └── when the caller is authorized for all streams - ├── when the provided address is zero + ├── when some amounts are zero + │ └── it should revert + └── when none of the amounts are zero + ├── when some amounts overdraw │ └── it should revert - └── when the provided address is not zero - ├── when some amounts are zero - │ └── it should revert - └── when none of the amounts are zero - ├── when some amounts overdraw - │ └── it should revert - └── when no amount overdraws - ├── it should make the withdrawals - ├── it should update the statuses - ├── it should update the withdrawn amounts - └── it should emit multiple {WithdrawFromLockupStream} events + └── when no amount overdraws + ├── it should make the withdrawals + ├── it should update the statuses + ├── it should update the withdrawn amounts + └── it should emit multiple {WithdrawFromLockupStream} events diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 745a7d5e4..8c488b240 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -16,6 +16,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr Withdraw_Integration_Shared_Test.setUp(); } + /*////////////////////////////////////////////////////////////////////////// + TESTS + //////////////////////////////////////////////////////////////////////////*/ + function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = @@ -40,100 +44,143 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } - function test_RevertWhen_CallerUnauthorized_Sender() + function test_RevertWhen_ToZeroAddress() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + vm.expectRevert(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector); + lockup.withdraw({ streamId: defaultStreamId, to: address(0), amount: withdrawAmount }); + } + + function test_RevertWhen_WithdrawAmountZero() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerUnauthorized + whenToNonZeroAddress { - // Make the Sender the caller in this test. - changePrank({ msgSender: users.sender }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, defaultStreamId)); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); + } - // Run the test. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + function test_RevertWhen_Overdraw() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenToNonZeroAddress + whenWithdrawAmountNotZero + { + uint128 withdrawableAmount = 0; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_InvalidSenderWithdrawal.selector, defaultStreamId, users.sender, users.sender + Errors.SablierV2Lockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.sender, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); } - function test_RevertWhen_CallerUnauthorized_MaliciousThirdParty() + function test_RevertWhen_CallerUnknown() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerUnauthorized + whenWithdrawAmountNotZero + whenNoOverdraw + whenWithdrawalAddressNotRecipient { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.eve) - ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); - } + address unknownCaller = address(0xCAFE); - function test_RevertWhen_FormerRecipient() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { - // Transfer the stream to Alice. - lockup.transferFrom(users.recipient, users.alice, defaultStreamId); + // Make Eve the caller in this test. + changePrank({ msgSender: unknownCaller }); // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector( + Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, + defaultStreamId, + unknownCaller, + unknownCaller + ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: unknownCaller, amount: withdrawAmount }); } - function test_RevertWhen_ToZeroAddress() + function test_RevertWhen_CallerSender() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized + whenWithdrawAmountNotZero + whenNoOverdraw + whenWithdrawalAddressNotRecipient { + // Make the Sender the caller in this test. + changePrank({ msgSender: users.sender }); + + // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector); - lockup.withdraw({ streamId: defaultStreamId, to: address(0), amount: withdrawAmount }); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, + defaultStreamId, + users.sender, + users.sender + ) + ); + lockup.withdraw({ streamId: defaultStreamId, to: users.sender, amount: withdrawAmount }); } - function test_RevertWhen_WithdrawAmountZero() + function test_RevertWhen_CallerFormerRecipient() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized - whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenWithdrawalAddressNotRecipient { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); + // Transfer the stream to Alice. + lockup.transferFrom(users.recipient, users.alice, defaultStreamId); + + // Run the test. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, + defaultStreamId, + users.recipient, + users.recipient + ) + ); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } - function test_RevertWhen_Overdraw() + function test_Withdraw_CallerApprovedOperator() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero + whenNoOverdraw + whenWithdrawalAddressNotRecipient { - uint128 withdrawableAmount = 0; - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2Lockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount - ) - ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); - } + // Approve the operator to handle the stream. + lockup.approve({ to: users.operator, tokenId: defaultStreamId }); - modifier whenNoOverdraw() { - _; + // Make the operator the caller in this test. + changePrank({ msgSender: users.operator }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Make the withdrawal. + lockup.withdraw({ streamId: defaultStreamId, to: users.operator, amount: defaults.WITHDRAW_AMOUNT() }); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); + uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } function test_Withdraw_SenderNotContract() @@ -141,10 +188,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressNotRecipient whenCallerRecipient { test_Withdraw_CallerRecipient(defaultStreamId, users.sender); @@ -159,10 +206,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressNotRecipient whenCallerRecipient givenSenderContract { @@ -176,15 +223,15 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr _; } - function test_Withdraw_ReetrancySender() + function test_Withdraw_ReentrancySender() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressNotRecipient whenCallerRecipient givenSenderContract givenSenderImplementsHook @@ -229,10 +276,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressNotRecipient whenCallerRecipient givenSenderContract givenSenderImplementsHook @@ -253,10 +300,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressNotRecipient whenCallerRecipient givenSenderContract givenSenderImplementsHook @@ -269,48 +316,41 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(streamId, address(goodSender)); } - function test_Withdraw_CallerRecipient(uint256 streamId, address sender) internal { + function test_Withdraw_CallerUnknownAddress() + external + whenNotDelegateCalled + givenNotNull + givenStreamNotDepleted + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + whenWithdrawalAddressIsRecipient + { + // Make the unknown address the caller in this test. + changePrank({ msgSender: address(0xCAFE) }); + // Simulate the passage of time. vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the hook if the sender is a contract. - if (sender.code.length > 0) { - vm.expectCall( - address(sender), - abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) - ) - ); - } - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); - uint128 expectedWithdrawnAmount = withdrawAmount; + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); + uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - function test_Withdraw_CallerApprovedOperator() + function test_Withdraw_CallerRecipient() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient { - // Approve the operator to handle the stream. - lockup.approve({ to: users.operator, tokenId: defaultStreamId }); - - // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); - // Simulate the passage of time. vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); @@ -333,10 +373,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender { // Warp to the stream's end. @@ -371,10 +411,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture { @@ -408,15 +448,15 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled { - test_Withdraw(defaultStreamId, users.recipient); + test_Withdraw_CallerSender(defaultStreamId, users.recipient); } modifier givenRecipientContract() { @@ -428,10 +468,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled @@ -440,7 +480,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Create the stream with a noop contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(noop)); - test_Withdraw(streamId, address(noop)); + test_Withdraw_CallerSender(streamId, address(noop)); } modifier givenRecipientImplementsHook() { @@ -452,10 +492,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled @@ -465,7 +505,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Create the stream with a reverting contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(revertingRecipient)); - test_Withdraw(streamId, address(revertingRecipient)); + test_Withdraw_CallerSender(streamId, address(revertingRecipient)); } modifier whenRecipientDoesNotRevert() { @@ -477,10 +517,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled @@ -526,10 +566,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero whenNoOverdraw + whenWithdrawalAddressIsRecipient whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled @@ -541,10 +581,40 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Create the stream with a contract as the stream's recipient. uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); - test_Withdraw(streamId, address(goodRecipient)); + test_Withdraw_CallerSender(streamId, address(goodRecipient)); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function test_Withdraw_CallerRecipient(uint256 streamId, address sender) internal { + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the hook if the sender is a contract. + if (sender.code.length > 0) { + vm.expectCall( + address(sender), + abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) + ) + ); + } + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 expectedWithdrawnAmount = withdrawAmount; + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - function test_Withdraw(uint256 streamId, address recipient) internal { + function test_Withdraw_CallerSender(uint256 streamId, address recipient) internal { // Set the withdraw amount to the default amount. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.tree b/test/integration/concrete/lockup/withdraw/withdraw.tree index 314fa95e1..fccd07685 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.tree +++ b/test/integration/concrete/lockup/withdraw/withdraw.tree @@ -8,90 +8,96 @@ withdraw.t.sol ├── given the stream's status is "DEPLETED" │ └── it should revert └── given the stream's status is not "DEPLETED" - ├── when the caller is unauthorized - │ ├── when the caller is the sender - │ │ └── it should revert - │ ├── when the caller is a malicious third party - │ │ └── it should revert - │ └── when the caller is a former recipient - │ └── it should revert - └── when the caller is authorized - ├── when the provided address is zero + ├── when the provided address is zero + │ └── it should revert + └── when the provided address is not zero + ├── when the withdraw amount is zero │ └── it should revert - └── when the provided address is not zero - ├── when the withdraw amount is zero + └── when the withdraw amount is not zero + ├── when the withdraw amount overdraws │ └── it should revert - └── when the withdraw amount is not zero - ├── when the withdraw amount overdraws - │ └── it should revert - └── when the withdraw amount does not overdraw - ├── when the caller is the recipient - │ ├── given the sender is not a contract - │ │ ├── it should make the withdrawal - │ │ └── it should update the withdrawn amount - │ └── given the sender is a contract - │ ├── given the sender does not implement the hook - │ │ ├── it should make the withdrawal - │ │ ├── it should update the withdrawn amount - │ │ ├── it should call the sender hook - │ │ └── it should ignore the revert - │ └── given the sender implements the hook - │ ├── when the sender reverts - │ │ ├── it should make the withdrawal - │ │ ├── it should update the withdrawn amount - │ │ ├── it should call the sender hook - │ │ └── it should ignore the revert - │ └── when the sender does not revert - │ ├── when there is reentrancy - │ │ ├── it should make multiple withdrawals - │ │ ├── it should update the withdrawn amounts - │ │ └── it should call the sender hooks - │ └── when there is no reentrancy - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the sender hook - │ ├── it should emit a {MetadataUpdate} event - │ └── it should emit a {WithdrawFromLockupStream} event - └── when the caller is an approved third party + └── when the withdraw amount does not overdraw + ├── when the withdrawal address is not the stream recipient + │ ├── when the caller is unknown + │ │ └── it should revert + │ ├── when the caller is the sender + │ │ └── it should revert + │ ├── when the caller is a former recipient + │ │ └── it should revert + │ ├── when the caller is an approved third party + │ │ ├── it should make the withdrawal + │ │ └── it should update the withdrawn amount + │ └── when the caller is the recipient + │ ├── given the sender is not a contract + │ │ ├── it should make the withdrawal + │ │ └── it should update the withdrawn amount + │ └── given the sender is a contract + │ ├── given the sender does not implement the hook + │ │ ├── it should make the withdrawal + │ │ ├── it should update the withdrawn amount + │ │ ├── it should call the sender hook + │ │ └── it should ignore the revert + │ └── given the sender implements the hook + │ ├── when the sender reverts + │ │ ├── it should make the withdrawal + │ │ ├── it should update the withdrawn amount + │ │ ├── it should call the sender hook + │ │ └── it should ignore the revert + │ └── when the sender does not revert + │ ├── when there is reentrancy + │ │ ├── it should make multiple withdrawals + │ │ ├── it should update the withdrawn amounts + │ │ └── it should call the sender hooks + │ └── when there is no reentrancy + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ ├── it should call the sender hook + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── when the withdrawal address is the stream recipient + ├── when the caller is unknown + │ ├── it should make the withdrawal + │ └── it should update the withdrawn amount + ├── when the caller is the recipient + │ ├── it should make the withdrawal + │ └── it should update the withdrawn amount + └── when the caller is the sender + ├── given the end time is not in the future │ ├── it should make the withdrawal - │ └── it should update the withdrawn amount - └── when the caller is the sender - ├── given the end time is not in the future + │ ├── it should mark the stream as depleted + │ └── it should make the stream not cancelable + └── given the end time is in the future + ├── given the stream has been canceled │ ├── it should make the withdrawal │ ├── it should mark the stream as depleted - │ └── it should make the stream not cancelable - └── given the end time is in the future - ├── given the stream has been canceled - │ ├── it should make the withdrawal - │ ├── it should mark the stream as depleted - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ ├── it should emit a {MetadataUpdate} event - │ └── it should emit a {WithdrawFromLockupStream} event - └── given the stream has not been canceled - ├── given the recipient is not a contract - │ └── it should make the withdrawal - │ └── it should update the withdrawn amount - └── given the recipient is a contract - ├── given the recipient does not implement the hook + │ ├── it should update the withdrawn amount + │ ├── it should call the recipient hook + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── given the stream has not been canceled + ├── given the recipient is not a contract + │ └── it should make the withdrawal + │ └── it should update the withdrawn amount + └── given the recipient is a contract + ├── given the recipient does not implement the hook + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ ├── it should call the recipient hook + │ └── it should ignore the revert + └── given the recipient implements the hook + ├── when the recipient reverts │ ├── it should make the withdrawal │ ├── it should update the withdrawn amount │ ├── it should call the recipient hook │ └── it should ignore the revert - └── given the recipient implements the hook - ├── when the recipient reverts - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when the recipient does not revert - ├── when there is reentrancy - │ ├── it should make multiple withdrawals - │ ├── it should update the withdrawn amounts - │ └── it should call the recipient hooks - └── when there is no reentrancy - ├── it should make the withdrawal - ├── it should update the withdrawn amount - ├── it should call the recipient hook - ├── it should emit a {MetadataUpdate} event - └── it should emit a {WithdrawFromLockupStream} event + └── when the recipient does not revert + ├── when there is reentrancy + │ ├── it should make multiple withdrawals + │ ├── it should update the withdrawn amounts + │ └── it should call the recipient hooks + └── when there is no reentrancy + ├── it should make the withdrawal + ├── it should update the withdrawn amount + ├── it should call the recipient hook + ├── it should emit a {MetadataUpdate} event + └── it should emit a {WithdrawFromLockupStream} event diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index c73d880f5..45fd367cc 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -44,10 +44,9 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is external whenNotDelegateCalled givenNotNull - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero - whenWithdrawAmountNotGreaterThanWithdrawableAmount + whenNoOverdraw { vm.assume(params.segments.length != 0); vm.assume(params.to != address(0)); diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/integration/fuzz/lockup/withdraw.t.sol index 6b9c8d3aa..4079206c5 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/integration/fuzz/lockup/withdraw.t.sol @@ -11,6 +11,39 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I Withdraw_Integration_Shared_Test.setUp(); } + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - Multiple caller addresses. + function testFuzz_Withdraw_UnknownCaller(address caller) + external + whenNotDelegateCalled + givenNotNull + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + { + vm.assume(caller != users.sender && caller != users.recipient); + + // Make the fuzzed address the caller in this test. + changePrank({ msgSender: caller }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Make the withdrawal. + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + + // Assert that the stream's status is still "STREAMING". + Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); + Lockup.Status expectedStatus = Lockup.Status.STREAMING; + assertEq(actualStatus, expectedStatus); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); + uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + } + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - Multiple values for the withdrawal address. @@ -19,10 +52,9 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I whenNotDelegateCalled givenNotNull givenStreamNotDepleted - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero - whenWithdrawAmountNotGreaterThanWithdrawableAmount + whenNoOverdraw { vm.assume(to != address(0)); @@ -62,10 +94,9 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I external whenNotDelegateCalled givenNotNull - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero - whenWithdrawAmountNotGreaterThanWithdrawableAmount + whenNoOverdraw whenCallerRecipient { timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); @@ -130,11 +161,9 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I external whenNotDelegateCalled givenNotNull - whenCallerAuthorized whenToNonZeroAddress whenWithdrawAmountNotZero - whenWithdrawAmountNotGreaterThanWithdrawableAmount - whenCallerRecipient + whenNoOverdraw whenStreamHasNotBeenCanceled { timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); diff --git a/test/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/integration/fuzz/lockup/withdrawMultiple.t.sol index 307889d33..7cabecba9 100644 --- a/test/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -18,7 +18,6 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is function testFuzz_WithdrawMultiple( uint256 timeJump, - address to, uint128 ongoingWithdrawAmount ) external @@ -31,14 +30,8 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is whenNoAmountZero whenNoAmountOverdraws { - vm.assume(to != address(0)); timeJump = _bound(timeJump, defaults.TOTAL_DURATION(), defaults.TOTAL_DURATION() * 2 - 1 seconds); - // Hard code the withdrawal address if the caller is the stream's sender. - if (caller == users.sender) { - to = users.recipient; - } - // Create a new stream with an end time double that of the default stream. changePrank({ msgSender: users.sender }); uint40 ongoingEndTime = defaults.END_TIME() + defaults.TOTAL_DURATION(); @@ -59,19 +52,29 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is ongoingWithdrawAmount = boundUint128(ongoingWithdrawAmount, 1, ongoingWithdrawableAmount); // Expect the withdrawals to be made. - expectCallToTransfer({ to: to, amount: ongoingWithdrawAmount }); - expectCallToTransfer({ to: to, amount: settledWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, amount: ongoingWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, amount: settledWithdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit WithdrawFromLockupStream({ streamId: ongoingStreamId, to: to, asset: dai, amount: ongoingWithdrawAmount }); + emit WithdrawFromLockupStream({ + streamId: ongoingStreamId, + to: users.recipient, + asset: dai, + amount: ongoingWithdrawAmount + }); vm.expectEmit({ emitter: address(lockup) }); - emit WithdrawFromLockupStream({ streamId: settledStreamId, to: to, asset: dai, amount: settledWithdrawAmount }); + emit WithdrawFromLockupStream({ + streamId: settledStreamId, + to: users.recipient, + asset: dai, + amount: settledWithdrawAmount + }); // Make the withdrawals. uint256[] memory streamIds = Solarray.uint256s(ongoingStreamId, settledStreamId); uint128[] memory amounts = Solarray.uint128s(ongoingWithdrawAmount, settledWithdrawAmount); - lockup.withdrawMultiple({ streamIds: streamIds, to: to, amounts: amounts }); + lockup.withdrawMultiple(streamIds, amounts); // Assert that the statuses have been updated. assertEq(lockup.statusOf(streamIds[0]), Lockup.Status.STREAMING, "status0"); diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 300b89f61..69fc8cb11 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -24,23 +24,23 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } - modifier whenCallerUnauthorized() { + modifier whenToNonZeroAddress() { _; } - modifier whenCallerAuthorized() { + modifier whenWithdrawAmountNotZero() { _; } - modifier whenToNonZeroAddress() { + modifier whenNoOverdraw() { _; } - modifier whenWithdrawAmountNotZero() { + modifier whenWithdrawalAddressNotRecipient() { _; } - modifier whenWithdrawAmountNotGreaterThanWithdrawableAmount() { + modifier whenWithdrawalAddressIsRecipient() { _; } From fb56467e365f938778520dfbd95ea2ae879ee1aa Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Sun, 21 Jan 2024 22:16:35 +0200 Subject: [PATCH 038/132] refactor: rename create functions --- script/Init.s.sol | 4 +- src/SablierV2LockupDynamic.sol | 14 +-- src/SablierV2LockupLinear.sol | 17 ++-- src/interfaces/ISablierV2LockupDynamic.sol | 8 +- src/interfaces/ISablierV2LockupLinear.sol | 6 +- src/libraries/Helpers.sol | 8 +- src/types/DataTypes.sol | 14 +-- test/fork/LockupDynamic.t.sol | 4 +- test/fork/LockupLinear.t.sol | 4 +- .../createWithDurations.t.sol} | 19 ++-- .../createWithDurations.tree} | 2 +- .../createWithTimestamps.t.sol} | 28 +++--- .../createWithTimestamps.tree} | 2 +- .../createWithDurations.t.sol | 2 +- .../createWithTimestamps.t.sol} | 25 ++--- .../createWithTimestamps.tree} | 2 +- ...Deltas.t.sol => createWithDurations.t.sol} | 16 ++-- ...tones.t.sol => createWithTimestamps.t.sol} | 22 ++--- .../lockup-dynamic/streamedAmountOf.t.sol | 12 +-- .../fuzz/lockup-dynamic/withdraw.t.sol | 4 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 8 +- ...Range.t.sol => createWithTimestamps.t.sol} | 18 ++-- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 8 +- .../lockup-linear/withdrawableAmountOf.t.sol | 8 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 92 +++++++++---------- ...Deltas.t.sol => createWithDurations.t.sol} | 2 +- ...tones.t.sol => createWithTimestamps.t.sol} | 2 +- .../shared/lockup-linear/LockupLinear.t.sol | 54 +++++------ ...Range.t.sol => createWithTimestamps.t.sol} | 2 +- .../handlers/LockupDynamicCreateHandler.sol | 16 ++-- .../handlers/LockupLinearCreateHandler.sol | 8 +- test/utils/Defaults.sol | 14 +-- 32 files changed, 227 insertions(+), 218 deletions(-) rename test/integration/concrete/lockup-dynamic/{create-with-deltas/createWithDeltas.t.sol => create-with-durations/createWithDurations.t.sol} (92%) rename test/integration/concrete/lockup-dynamic/{create-with-deltas/createWithDeltas.tree => create-with-durations/createWithDurations.tree} (97%) rename test/integration/concrete/lockup-dynamic/{create-with-milestones/createWithMilestones.t.sol => create-with-timestamps/createWithTimestamps.t.sol} (93%) rename test/integration/concrete/lockup-dynamic/{create-with-milestones/createWithMilestones.tree => create-with-timestamps/createWithTimestamps.tree} (99%) rename test/integration/concrete/lockup-linear/{create-with-range/createWithRange.t.sol => create-with-timestamps/createWithTimestamps.t.sol} (90%) rename test/integration/concrete/lockup-linear/{create-with-range/createWithRange.tree => create-with-timestamps/createWithTimestamps.tree} (99%) rename test/integration/fuzz/lockup-dynamic/{createWithDeltas.t.sol => createWithDurations.t.sol} (91%) rename test/integration/fuzz/lockup-dynamic/{createWithMilestones.t.sol => createWithTimestamps.t.sol} (95%) rename test/integration/fuzz/lockup-linear/{createWithRange.t.sol => createWithTimestamps.t.sol} (94%) rename test/integration/shared/lockup-dynamic/{createWithDeltas.t.sol => createWithDurations.t.sol} (85%) rename test/integration/shared/lockup-dynamic/{createWithMilestones.t.sol => createWithTimestamps.t.sol} (94%) rename test/integration/shared/lockup-linear/{createWithRange.t.sol => createWithTimestamps.t.sol} (89%) diff --git a/script/Init.s.sol b/script/Init.s.sol index 4186ac3e0..3979c9bee 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -81,8 +81,8 @@ contract Init is BaseScript { LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](2); segments[0] = LockupDynamic.SegmentWithDelta({ amount: 2500e18, exponent: ud2x18(3.14e18), delta: 1 hours }); segments[1] = LockupDynamic.SegmentWithDelta({ amount: 7500e18, exponent: ud2x18(0.5e18), delta: 1 weeks }); - lockupDynamic.createWithDeltas( - LockupDynamic.CreateWithDeltas({ + lockupDynamic.createWithDurations( + LockupDynamic.CreateWithDurations({ sender: sender, recipient: recipient, totalAmount: 10_000e18, diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 03fc8c8d5..060b5aa9c 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -267,7 +267,7 @@ contract SablierV2LockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2LockupDynamic - function createWithDeltas(LockupDynamic.CreateWithDeltas calldata params) + function createWithDurations(LockupDynamic.CreateWithDurations calldata params) external override noDelegateCall @@ -277,8 +277,8 @@ contract SablierV2LockupDynamic is LockupDynamic.Segment[] memory segments = Helpers.checkDeltasAndCalculateMilestones(params.segments); // Checks, Effects and Interactions: create the stream. - streamId = _createWithMilestones( - LockupDynamic.CreateWithMilestones({ + streamId = _createWithTimestamps( + LockupDynamic.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, @@ -293,14 +293,14 @@ contract SablierV2LockupDynamic is } /// @inheritdoc ISablierV2LockupDynamic - function createWithMilestones(LockupDynamic.CreateWithMilestones calldata params) + function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) external override noDelegateCall returns (uint256 streamId) { // Checks, Effects and Interactions: create the stream. - streamId = _createWithMilestones(params); + streamId = _createWithTimestamps(params); } /*////////////////////////////////////////////////////////////////////////// @@ -537,7 +537,7 @@ contract SablierV2LockupDynamic is } /// @dev See the documentation for the user-facing functions that call this internal function. - function _createWithMilestones(LockupDynamic.CreateWithMilestones memory params) + function _createWithTimestamps(LockupDynamic.CreateWithTimestamps memory params) internal returns (uint256 streamId) { @@ -550,7 +550,7 @@ contract SablierV2LockupDynamic is Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); // Checks: validate the user-provided parameters. - Helpers.checkCreateWithMilestones(createAmounts.deposit, params.segments, MAX_SEGMENT_COUNT, params.startTime); + Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.segments, MAX_SEGMENT_COUNT, params.startTime); // Load the stream id in a variable. streamId = nextStreamId; diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 56fe191c9..a1eb4f98f 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -261,15 +261,15 @@ contract SablierV2LockupLinear is range.start = uint40(block.timestamp); // Calculate the cliff time and the end time. It is safe to use unchecked arithmetic because - // {_createWithRange} will nonetheless check that the end time is greater than the cliff time, + // {_createWithTimestamps} will nonetheless check that the end time is greater than the cliff time, // and also that the cliff time is greater than or equal to the start time. unchecked { range.cliff = range.start + params.durations.cliff; range.end = range.start + params.durations.total; } // Checks, Effects and Interactions: create the stream. - streamId = _createWithRange( - LockupLinear.CreateWithRange({ + streamId = _createWithTimestamps( + LockupLinear.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, @@ -283,14 +283,14 @@ contract SablierV2LockupLinear is } /// @inheritdoc ISablierV2LockupLinear - function createWithRange(LockupLinear.CreateWithRange calldata params) + function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) external override noDelegateCall returns (uint256 streamId) { // Checks, Effects and Interactions: create the stream. - streamId = _createWithRange(params); + streamId = _createWithTimestamps(params); } /*////////////////////////////////////////////////////////////////////////// @@ -452,7 +452,10 @@ contract SablierV2LockupLinear is } /// @dev See the documentation for the user-facing functions that call this internal function. - function _createWithRange(LockupLinear.CreateWithRange memory params) internal returns (uint256 streamId) { + function _createWithTimestamps(LockupLinear.CreateWithTimestamps memory params) + internal + returns (uint256 streamId) + { // Safe Interactions: query the protocol fee. This is safe because it's a known Sablier contract that does // not call other unknown contracts. UD60x18 protocolFee = comptroller.protocolFees(params.asset); @@ -462,7 +465,7 @@ contract SablierV2LockupLinear is Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); // Checks: validate the user-provided parameters. - Helpers.checkCreateWithRange(createAmounts.deposit, params.range); + Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.range); // Load the stream id. streamId = nextStreamId; diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index e60cb3fee..bf030bd99 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -98,11 +98,13 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @dev Emits a {Transfer} and {CreateLockupDynamicStream} event. /// /// Requirements: - /// - All requirements in {createWithMilestones} must be met for the calculated parameters. + /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The id of the newly created stream. - function createWithDeltas(LockupDynamic.CreateWithDeltas calldata params) external returns (uint256 streamId); + function createWithDurations(LockupDynamic.CreateWithDurations calldata params) + external + returns (uint256 streamId); /// @notice Creates a stream with the provided segment milestones, implying the end time from the last milestone. /// The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. @@ -127,7 +129,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The id of the newly created stream. - function createWithMilestones(LockupDynamic.CreateWithMilestones calldata params) + function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) external returns (uint256 streamId); } diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index 95ecd1f16..a8f066896 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -92,7 +92,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @dev Emits a {Transfer} and {CreateLockupLinearStream} event. /// /// Requirements: - /// - All requirements in {createWithRange} must be met for the calculated parameters. + /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The id of the newly created stream. @@ -120,5 +120,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The id of the newly created stream. - function createWithRange(LockupLinear.CreateWithRange calldata params) external returns (uint256 streamId); + function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) + external + returns (uint256 streamId); } diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index cfc9e2d54..319cc28b9 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -55,8 +55,8 @@ library Helpers { amounts.deposit = totalAmount - amounts.protocolFee - amounts.brokerFee; } - /// @dev Checks the parameters of the {SablierV2LockupDynamic-_createWithMilestones} function. - function checkCreateWithMilestones( + /// @dev Checks the parameters of the {SablierV2LockupDynamic-_createWithTimestamps} function. + function checkCreateWithTimestamps( uint128 depositAmount, LockupDynamic.Segment[] memory segments, uint256 maxSegmentCount, @@ -85,8 +85,8 @@ library Helpers { _checkSegments(segments, depositAmount, startTime); } - /// @dev Checks the parameters of the {SablierV2LockupLinear-_createWithRange} function. - function checkCreateWithRange(uint128 depositAmount, LockupLinear.Range memory range) internal view { + /// @dev Checks the parameters of the {SablierV2LockupLinear-_createWithTimestamps} function. + function checkCreateWithTimestamps(uint128 depositAmount, LockupLinear.Range memory range) internal view { // Checks: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierV2Lockup_DepositAmountZero(); diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index ce6366ed5..1a9337a04 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -70,7 +70,7 @@ library Lockup { /// @notice Namespace for the structs used in {SablierV2LockupDynamic}. library LockupDynamic { - /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithDeltas} function. + /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithDurations} function. /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -83,7 +83,7 @@ library LockupDynamic { /// starting from `block.timestamp` and adding each delta to the previous milestone. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. - struct CreateWithDeltas { + struct CreateWithDurations { address sender; address recipient; uint128 totalAmount; @@ -94,7 +94,7 @@ library LockupDynamic { Broker broker; } - /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithMilestones} + /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithTimestamps} /// function. /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. @@ -108,7 +108,7 @@ library LockupDynamic { /// @param segments Segments used to compose the custom streaming curve. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. - struct CreateWithMilestones { + struct CreateWithTimestamps { address sender; address recipient; uint128 totalAmount; @@ -139,7 +139,7 @@ library LockupDynamic { uint40 milestone; } - /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDeltas}. + /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDurations}. /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals. /// @param exponent The exponent of this segment, denoted as a fixed-point number. /// @param delta The time difference in seconds between this segment and the previous one. @@ -207,7 +207,7 @@ library LockupLinear { Broker broker; } - /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithRange} function. + /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithTimestamps} function. /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -220,7 +220,7 @@ library LockupLinear { /// timestamps. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. - struct CreateWithRange { + struct CreateWithTimestamps { address sender; address recipient; uint128 totalAmount; diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index ea1f40f5a..4e7b0c2de 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -177,8 +177,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { }); // Create the stream. - lockupDynamic.createWithMilestones( - LockupDynamic.CreateWithMilestones({ + lockupDynamic.createWithTimestamps( + LockupDynamic.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index 7207590fd..d390e49d0 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -179,8 +179,8 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { }); // Create the stream. - lockupLinear.createWithRange( - LockupLinear.CreateWithRange({ + lockupLinear.createWithTimestamps( + LockupLinear.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, diff --git a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol similarity index 92% rename from test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol rename to test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 4affdbb97..aeac29e30 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -7,26 +7,27 @@ import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic. import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithDeltas_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithDeltas.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithDurations.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; -contract CreateWithDeltas_LockupDynamic_Integration_Concrete_Test is +contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, - CreateWithDeltas_Integration_Shared_Test + CreateWithDurations_Integration_Shared_Test { function setUp() public virtual - override(LockupDynamic_Integration_Concrete_Test, CreateWithDeltas_Integration_Shared_Test) + override(LockupDynamic_Integration_Concrete_Test, CreateWithDurations_Integration_Shared_Test) { LockupDynamic_Integration_Concrete_Test.setUp(); - CreateWithDeltas_Integration_Shared_Test.setUp(); + CreateWithDurations_Integration_Shared_Test.setUp(); streamId = lockupDynamic.nextStreamId(); } /// @dev it should revert. function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2LockupDynamic.createWithDeltas, defaults.createWithDeltas()); + bytes memory callData = + abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, defaults.createWithDurationsLD()); (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -44,7 +45,7 @@ contract CreateWithDeltas_LockupDynamic_Integration_Concrete_Test is whenLoopCalculationsDoNotOverflowBlockGasLimit { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDeltas().segments; + LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDurationsLD().segments; segments[1].delta = 0; uint256 index = 1; vm.expectRevert( @@ -66,7 +67,7 @@ contract CreateWithDeltas_LockupDynamic_Integration_Concrete_Test is { unchecked { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDeltas().segments; + LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDurationsLD().segments; segments[0].delta = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( @@ -111,7 +112,7 @@ contract CreateWithDeltas_LockupDynamic_Integration_Concrete_Test is } } - function test_CreateWithDeltas() + function test_CreateWithDurations() external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit diff --git a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.tree b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree similarity index 97% rename from test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.tree rename to test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree index 3824747f3..e3a5c988a 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree @@ -1,4 +1,4 @@ -createWithDeltas.t.sol +createWithDurations.t.sol ├── when delegate called │ └── it should revert └── when not delegate called diff --git a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol similarity index 93% rename from test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol rename to test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 5a7b028b6..b39b7251a 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -9,25 +9,25 @@ import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic. import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithMilestones_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithMilestones.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; -contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is +contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, - CreateWithMilestones_Integration_Shared_Test + CreateWithTimestamps_Integration_Shared_Test { function setUp() public virtual - override(LockupDynamic_Integration_Concrete_Test, CreateWithMilestones_Integration_Shared_Test) + override(LockupDynamic_Integration_Concrete_Test, CreateWithTimestamps_Integration_Shared_Test) { LockupDynamic_Integration_Concrete_Test.setUp(); - CreateWithMilestones_Integration_Shared_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); } function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupDynamic.createWithMilestones, defaults.createWithMilestones()); + abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, defaults.createWithTimestampsLD()); (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -208,7 +208,7 @@ contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: brokerFee }); params.totalAmount = depositAmount; @@ -222,7 +222,7 @@ contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is ); // Create the stream. - lockupDynamic.createWithMilestones(params); + lockupDynamic.createWithTimestamps(params); } function test_RevertGiven_ProtocolFeeTooHigh() @@ -299,7 +299,7 @@ contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithAsset(IERC20(nonContract)); } - function test_CreateWithMilestones_AssetMissingReturnValue() + function test_CreateWithTimestamps_AssetMissingReturnValue() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -315,10 +315,10 @@ contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is whenBrokerFeeNotTooHigh whenAssetContract { - testCreateWithMilestones(address(usdt)); + testCreateWithTimestamps(address(usdt)); } - function test_CreateWithMilestones() + function test_CreateWithTimestamps() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -335,11 +335,11 @@ contract CreateWithMilestones_LockupDynamic_Integration_Concrete_Test is whenAssetContract whenAssetERC20 { - testCreateWithMilestones(address(dai)); + testCreateWithTimestamps(address(dai)); } - /// @dev Shared logic between {test_CreateWithMilestones_AssetMissingReturnValue} and {test_CreateWithMilestones}. - function testCreateWithMilestones(address asset) internal { + /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. + function testCreateWithTimestamps(address asset) internal { // Make the Sender the stream's funder. address funder = users.sender; diff --git a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.tree b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree similarity index 99% rename from test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.tree rename to test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index c90aecfc5..6debf4ca6 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-milestones/createWithMilestones.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -1,4 +1,4 @@ -createWithMilestones.t.sol +createWithTimestamps.t.sol ├── when delegate called │ └── it should revert └── when not delegate called diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index f01eb9415..835b7af64 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -23,7 +23,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupLinear.createWithDurations, defaults.createWithDurations()); + abi.encodeCall(ISablierV2LockupLinear.createWithDurations, defaults.createWithDurationsLL()); (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } diff --git a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol similarity index 90% rename from test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol rename to test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 14c5f4018..1cc002290 100644 --- a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -8,24 +8,25 @@ import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.so import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithRange_Integration_Shared_Test } from "../../../shared/lockup-linear/createWithRange.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup-linear/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; -contract CreateWithRange_LockupLinear_Integration_Concrete_Test is +contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, - CreateWithRange_Integration_Shared_Test + CreateWithTimestamps_Integration_Shared_Test { function setUp() public virtual - override(LockupLinear_Integration_Concrete_Test, CreateWithRange_Integration_Shared_Test) + override(LockupLinear_Integration_Concrete_Test, CreateWithTimestamps_Integration_Shared_Test) { LockupLinear_Integration_Concrete_Test.setUp(); - CreateWithRange_Integration_Shared_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2LockupLinear.createWithRange, defaults.createWithRange()); + bytes memory callData = + abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, defaults.createWithTimestampsLL()); (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -146,7 +147,7 @@ contract CreateWithRange_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithAsset(IERC20(nonContract)); } - function test_CreateWithRange_AssetMissingReturnValue() + function test_CreateWithTimestamps_AssetMissingReturnValue() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -158,10 +159,10 @@ contract CreateWithRange_LockupLinear_Integration_Concrete_Test is whenBrokerFeeNotTooHigh whenAssetContract { - testCreateWithRange(address(usdt)); + testCreateWithTimestamps(address(usdt)); } - function test_CreateWithRange() + function test_CreateWithTimestamps() external whenNotDelegateCalled whenDepositAmountNotZero @@ -173,11 +174,11 @@ contract CreateWithRange_LockupLinear_Integration_Concrete_Test is whenAssetContract whenAssetERC20 { - testCreateWithRange(address(dai)); + testCreateWithTimestamps(address(dai)); } - /// @dev Shared logic between {test_CreateWithRange_AssetMissingReturnValue} and {test_CreateWithRange}. - function testCreateWithRange(address asset) internal { + /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. + function testCreateWithTimestamps(address asset) internal { // Make the Sender the stream's funder. address funder = users.sender; diff --git a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.tree b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree similarity index 99% rename from test/integration/concrete/lockup-linear/create-with-range/createWithRange.tree rename to test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree index 6d810042a..407705603 100644 --- a/test/integration/concrete/lockup-linear/create-with-range/createWithRange.tree +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree @@ -1,4 +1,4 @@ -createWithRange.t.sol +createWithTimestamps.t.sol ├── when delegate called │ └── it should revert └── when not delegate called diff --git a/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol similarity index 91% rename from test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol rename to test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 87a61d646..81d7ca19c 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDeltas.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -3,20 +3,20 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithDeltas_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithDeltas.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithDurations.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; -contract CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test is +contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test, - CreateWithDeltas_Integration_Shared_Test + CreateWithDurations_Integration_Shared_Test { function setUp() public virtual - override(LockupDynamic_Integration_Fuzz_Test, CreateWithDeltas_Integration_Shared_Test) + override(LockupDynamic_Integration_Fuzz_Test, CreateWithDurations_Integration_Shared_Test) { LockupDynamic_Integration_Fuzz_Test.setUp(); - CreateWithDeltas_Integration_Shared_Test.setUp(); + CreateWithDurations_Integration_Shared_Test.setUp(); } struct Vars { @@ -37,7 +37,7 @@ contract CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test is uint128 totalAmount; } - function testFuzz_CreateWithDeltas(LockupDynamic.SegmentWithDelta[] memory segments) + function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDelta[] memory segments) external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit @@ -98,11 +98,11 @@ contract CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test is }); // Create the stream. - LockupDynamic.CreateWithDeltas memory params = defaults.createWithDeltas(); + LockupDynamic.CreateWithDurations memory params = defaults.createWithDurationsLD(); params.segments = segments; params.totalAmount = vars.totalAmount; params.transferable = true; - lockupDynamic.createWithDeltas(params); + lockupDynamic.createWithDurations(params); // Check if the stream is settled. It is possible for a Lockup Dynamic stream to settle at the time of creation // because some segment amounts can be zero. diff --git a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol similarity index 95% rename from test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol rename to test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 6db69943c..0bf50c093 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithMilestones.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -7,20 +7,20 @@ import { stdError } from "forge-std/src/StdError.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithMilestones_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithMilestones.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; -contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is +contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test, - CreateWithMilestones_Integration_Shared_Test + CreateWithTimestamps_Integration_Shared_Test { function setUp() public virtual - override(LockupDynamic_Integration_Fuzz_Test, CreateWithMilestones_Integration_Shared_Test) + override(LockupDynamic_Integration_Fuzz_Test, CreateWithTimestamps_Integration_Shared_Test) { LockupDynamic_Integration_Fuzz_Test.setUp(); - CreateWithMilestones_Integration_Shared_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); } function testFuzz_RevertWhen_SegmentCountTooHigh(uint256 segmentCount) @@ -111,7 +111,7 @@ contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: brokerFee }); params.totalAmount = depositAmount; @@ -125,7 +125,7 @@ contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is ); // Create the stream. - lockupDynamic.createWithMilestones(params); + lockupDynamic.createWithTimestamps(params); } function testFuzz_RevertWhen_ProtocolFeeTooHigh(UD60x18 protocolFee) @@ -201,9 +201,9 @@ contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is /// - Start time equal and not equal to the first segment milestone /// - Multiple values for the broker fee, including zero /// - Multiple values for the protocol fee, including zero - function testFuzz_CreateWithMilestones( + function testFuzz_CreateWithTimestamps( address funder, - LockupDynamic.CreateWithMilestones memory params, + LockupDynamic.CreateWithTimestamps memory params, UD60x18 protocolFee ) external @@ -285,8 +285,8 @@ contract CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test is }); // Create the stream. - lockupDynamic.createWithMilestones( - LockupDynamic.CreateWithMilestones({ + lockupDynamic.createWithTimestamps( + LockupDynamic.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 66f2dcca7..567b8f587 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -53,11 +53,11 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: segment.amount }); // Create the stream with the fuzzed segment. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: ZERO }); params.segments = segments; params.totalAmount = segment.amount; - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; @@ -118,11 +118,11 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: ZERO }); params.segments = segments; params.totalAmount = totalAmount; - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; @@ -170,11 +170,11 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: ZERO }); params.segments = segments; params.totalAmount = totalAmount; - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Warp to the future for the first time. vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index 45fd367cc..d88c7be2c 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -72,11 +72,11 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is changePrank({ msgSender: users.sender }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithMilestones memory createParams = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLD(); createParams.totalAmount = vars.totalAmount; createParams.segments = params.segments; - vars.streamId = lockupDynamic.createWithMilestones(createParams); + vars.streamId = lockupDynamic.createWithTimestamps(createParams); // Simulate the passage of time. vm.warp({ timestamp: defaults.START_TIME() + params.timeJump }); diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index e44e47485..e604db5df 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -42,10 +42,10 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = defaults.DEPOSIT_AMOUNT(); - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; @@ -92,10 +92,10 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithMilestones memory params = defaults.createWithMilestones(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = defaults.DEPOSIT_AMOUNT(); - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. vm.warp({ timestamp: currentTime }); diff --git a/test/integration/fuzz/lockup-linear/createWithRange.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol similarity index 94% rename from test/integration/fuzz/lockup-linear/createWithRange.t.sol rename to test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index e82fb3123..1916ea86f 100644 --- a/test/integration/fuzz/lockup-linear/createWithRange.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -6,20 +6,20 @@ import { MAX_UD60x18, UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithRange_Integration_Shared_Test } from "../../shared/lockup-linear/createWithRange.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-linear/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; -contract CreateWithRange_LockupLinear_Integration_Fuzz_Test is +contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear_Integration_Fuzz_Test, - CreateWithRange_Integration_Shared_Test + CreateWithTimestamps_Integration_Shared_Test { function setUp() public virtual - override(LockupLinear_Integration_Fuzz_Test, CreateWithRange_Integration_Shared_Test) + override(LockupLinear_Integration_Fuzz_Test, CreateWithTimestamps_Integration_Shared_Test) { LockupLinear_Integration_Fuzz_Test.setUp(); - CreateWithRange_Integration_Shared_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); } function testFuzz_RevertWhen_StartTimeGreaterThanCliffTime(uint40 startTime) @@ -123,9 +123,9 @@ contract CreateWithRange_LockupLinear_Integration_Fuzz_Test is /// - Multiple values for the cliff time and the end time /// - Multiple values for the broker fee, including zero /// - Multiple values for the protocol fee, including zero - function testFuzz_CreateWithRange( + function testFuzz_CreateWithTimestamps( address funder, - LockupLinear.CreateWithRange memory params, + LockupLinear.CreateWithTimestamps memory params, UD60x18 protocolFee ) external @@ -196,8 +196,8 @@ contract CreateWithRange_LockupLinear_Integration_Fuzz_Test is }); // Create the stream. - lockupLinear.createWithRange( - LockupLinear.CreateWithRange({ + lockupLinear.createWithTimestamps( + LockupLinear.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index f738bf2a4..98bbd1656 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -67,10 +67,10 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithRange memory params = defaults.createWithRange(); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithRange(params); + uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; @@ -101,9 +101,9 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithRange memory params = defaults.createWithRange(); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithRange(params); + uint256 streamId = lockupLinear.createWithTimestamps(params); // Warp to the future for the first time. vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index a76aa21e9..d0b93bc64 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -64,10 +64,10 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithRange memory params = defaults.createWithRange(); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithRange(params); + uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; @@ -119,10 +119,10 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithRange memory params = defaults.createWithRange(); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithRange(params); + uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. vm.warp({ timestamp: currentTime }); diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 5e1bd327e..046b1af22 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -10,8 +10,8 @@ import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; /// @notice Common testing logic needed across {SablierV2LockupDynamic} integration tests. abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Shared_Test { struct CreateParams { - LockupDynamic.CreateWithDeltas createWithDeltas; - LockupDynamic.CreateWithMilestones createWithMilestones; + LockupDynamic.CreateWithDurations createWithDurations; + LockupDynamic.CreateWithTimestamps createWithTimestamps; } /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. @@ -21,54 +21,54 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh function setUp() public virtual override { Lockup_Integration_Shared_Test.setUp(); - _params.createWithDeltas.sender = users.sender; - _params.createWithDeltas.recipient = users.recipient; - _params.createWithDeltas.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithDeltas.asset = dai; - _params.createWithDeltas.cancelable = true; - _params.createWithDeltas.transferable = true; - _params.createWithDeltas.broker = defaults.broker(); - - _params.createWithMilestones.sender = users.sender; - _params.createWithMilestones.recipient = users.recipient; - _params.createWithMilestones.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithMilestones.asset = dai; - _params.createWithMilestones.cancelable = true; - _params.createWithMilestones.transferable = true; - _params.createWithMilestones.startTime = defaults.START_TIME(); - _params.createWithMilestones.broker = defaults.broker(); + _params.createWithDurations.sender = users.sender; + _params.createWithDurations.recipient = users.recipient; + _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); + _params.createWithDurations.asset = dai; + _params.createWithDurations.cancelable = true; + _params.createWithDurations.transferable = true; + _params.createWithDurations.broker = defaults.broker(); + + _params.createWithTimestamps.sender = users.sender; + _params.createWithTimestamps.recipient = users.recipient; + _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); + _params.createWithTimestamps.asset = dai; + _params.createWithTimestamps.cancelable = true; + _params.createWithTimestamps.transferable = true; + _params.createWithTimestamps.startTime = defaults.START_TIME(); + _params.createWithTimestamps.broker = defaults.broker(); // See https://github.com/ethereum/solidity/issues/12783 LockupDynamic.SegmentWithDelta[] memory segmentsWithDeltas = defaults.segmentsWithDeltas(); LockupDynamic.Segment[] memory segments = defaults.segments(); for (uint256 i = 0; i < defaults.SEGMENT_COUNT(); ++i) { - _params.createWithDeltas.segments.push(segmentsWithDeltas[i]); - _params.createWithMilestones.segments.push(segments[i]); + _params.createWithDurations.segments.push(segmentsWithDeltas[i]); + _params.createWithTimestamps.segments.push(segments[i]); } } /// @dev Creates the default stream. function createDefaultStream() internal override returns (uint256 streamId) { - streamId = lockupDynamic.createWithMilestones(_params.createWithMilestones); + streamId = lockupDynamic.createWithTimestamps(_params.createWithTimestamps); } /// @dev Creates the default stream with the provided asset. function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.asset = asset; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided broker. function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.broker = broker; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with deltas. function createDefaultStreamWithDeltas() internal returns (uint256 streamId) { - streamId = lockupDynamic.createWithDeltas(_params.createWithDeltas); + streamId = lockupDynamic.createWithDurations(_params.createWithDurations); } /// @dev Creates the default stream with the provided deltas. @@ -76,45 +76,45 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh internal returns (uint256 streamId) { - LockupDynamic.CreateWithDeltas memory params = _params.createWithDeltas; + LockupDynamic.CreateWithDurations memory params = _params.createWithDurations; params.segments = segments; - streamId = lockupDynamic.createWithDeltas(params); + streamId = lockupDynamic.createWithDurations(params); } /// @dev Creates the default stream with the provided end time. function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.segments[1].milestone = endTime; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates a stream that will not be cancelable. function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.cancelable = false; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.transferable = false; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided range. function createDefaultStreamWithRange(LockupDynamic.Range memory range) internal returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.startTime = range.start; params.segments[1].milestone = range.end; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided recipient. function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.recipient = recipient; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided segments. @@ -122,29 +122,29 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh internal returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.segments = segments; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided sender. function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.sender = sender; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided start time.. function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.startTime = startTime; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } /// @dev Creates the default stream with the provided total amount. function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithMilestones memory params = _params.createWithMilestones; + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.totalAmount = totalAmount; - streamId = lockupDynamic.createWithMilestones(params); + streamId = lockupDynamic.createWithTimestamps(params); } } diff --git a/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol b/test/integration/shared/lockup-dynamic/createWithDurations.t.sol similarity index 85% rename from test/integration/shared/lockup-dynamic/createWithDeltas.t.sol rename to test/integration/shared/lockup-dynamic/createWithDurations.t.sol index 66ae9dcd4..b9687b7a1 100644 --- a/test/integration/shared/lockup-dynamic/createWithDeltas.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithDurations.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; -contract CreateWithDeltas_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithDurations_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { diff --git a/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol similarity index 94% rename from test/integration/shared/lockup-dynamic/createWithMilestones.t.sol rename to test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol index 34c08fa11..3027fdb8e 100644 --- a/test/integration/shared/lockup-dynamic/createWithMilestones.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; -contract CreateWithMilestones_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithTimestamps_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 2d90706fd..87315c0fa 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -11,7 +11,7 @@ import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Shared_Test { struct Params { LockupLinear.CreateWithDurations createWithDurations; - LockupLinear.CreateWithRange createWithRange; + LockupLinear.CreateWithTimestamps createWithTimestamps; } /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. @@ -20,27 +20,27 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha function setUp() public virtual override { Lockup_Integration_Shared_Test.setUp(); - _params.createWithDurations = defaults.createWithDurations(); - _params.createWithRange = defaults.createWithRange(); + _params.createWithDurations = defaults.createWithDurationsLL(); + _params.createWithTimestamps = defaults.createWithTimestampsLL(); } /// @dev Creates the default stream. function createDefaultStream() internal override returns (uint256 streamId) { - streamId = lockupLinear.createWithRange(_params.createWithRange); + streamId = lockupLinear.createWithTimestamps(_params.createWithTimestamps); } /// @dev Creates the default stream with the provided address. function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.asset = asset; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided broker. function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.broker = broker; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with durations. @@ -60,60 +60,60 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha /// @dev Creates the default stream that is not cancelable. function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.cancelable = false; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.transferable = false; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided end time. function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.range.end = endTime; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided createWithRange. - function createDefaultStreamWithRange(LockupLinear.Range memory createWithRange) + /// @dev Creates the default stream with the provided createWithTimestamps. + function createDefaultStreamWithRange(LockupLinear.Range memory createWithTimestamps) internal returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; - params.range = createWithRange; - streamId = lockupLinear.createWithRange(params); + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.range = createWithTimestamps; + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided recipient. function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.recipient = recipient; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided sender. function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.sender = sender; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided start time. function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.range.start = startTime; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } /// @dev Creates the default stream with the provided total amount. function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { - LockupLinear.CreateWithRange memory params = _params.createWithRange; + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.totalAmount = totalAmount; - streamId = lockupLinear.createWithRange(params); + streamId = lockupLinear.createWithTimestamps(params); } } diff --git a/test/integration/shared/lockup-linear/createWithRange.t.sol b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol similarity index 89% rename from test/integration/shared/lockup-linear/createWithRange.t.sol rename to test/integration/shared/lockup-linear/createWithTimestamps.t.sol index 2e7c59223..df2734c6d 100644 --- a/test/integration/shared/lockup-linear/createWithRange.t.sol +++ b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; -abstract contract CreateWithRange_Integration_Shared_Test is LockupLinear_Integration_Shared_Test { +abstract contract CreateWithTimestamps_Integration_Shared_Test is LockupLinear_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index b101c2873..67af327ed 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -45,12 +45,12 @@ contract LockupDynamicCreateHandler is BaseHandler { HANDLER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - function createWithDeltas( + function createWithDurations( uint256 timeJumpSeed, - LockupDynamic.CreateWithDeltas memory params + LockupDynamic.CreateWithDurations memory params ) public - instrument("createWithDeltas") + instrument("createWithDurations") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -87,18 +87,18 @@ contract LockupDynamicCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - uint256 streamId = lockupDynamic.createWithDeltas(params); + uint256 streamId = lockupDynamic.createWithDurations(params); // Store the stream id. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } - function createWithMilestones( + function createWithTimestamps( uint256 timeJumpSeed, - LockupDynamic.CreateWithMilestones memory params + LockupDynamic.CreateWithTimestamps memory params ) public - instrument("createWithMilestones") + instrument("createWithTimestamps") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -135,7 +135,7 @@ contract LockupDynamicCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - uint256 streamId = lockupDynamic.createWithMilestones(params); + uint256 streamId = lockupDynamic.createWithTimestamps(params); // Store the stream id. lockupStore.pushStreamId(streamId, params.sender, params.recipient); diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index af048de0a..1635c3f03 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -77,12 +77,12 @@ contract LockupLinearCreateHandler is BaseHandler { lockupStore.pushStreamId(streamId, params.sender, params.recipient); } - function createWithRange( + function createWithTimestamps( uint256 timeJumpSeed, - LockupLinear.CreateWithRange memory params + LockupLinear.CreateWithTimestamps memory params ) public - instrument("createWithRange") + instrument("createWithTimestamps") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -114,7 +114,7 @@ contract LockupLinearCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - uint256 streamId = lockupLinear.createWithRange(params); + uint256 streamId = lockupLinear.createWithTimestamps(params); // Store the stream id. lockupStore.pushStreamId(streamId, params.sender, params.recipient); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 244bfbff0..73af3e950 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -181,8 +181,8 @@ contract Defaults is Constants { PARAMS //////////////////////////////////////////////////////////////////////////*/ - function createWithDeltas() public view returns (LockupDynamic.CreateWithDeltas memory) { - return LockupDynamic.CreateWithDeltas({ + function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { + return LockupDynamic.CreateWithDurations({ sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, @@ -194,7 +194,7 @@ contract Defaults is Constants { }); } - function createWithDurations() public view returns (LockupLinear.CreateWithDurations memory) { + function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { return LockupLinear.CreateWithDurations({ sender: users.sender, recipient: users.recipient, @@ -207,8 +207,8 @@ contract Defaults is Constants { }); } - function createWithMilestones() public view returns (LockupDynamic.CreateWithMilestones memory) { - return LockupDynamic.CreateWithMilestones({ + function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { + return LockupDynamic.CreateWithTimestamps({ sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, @@ -221,8 +221,8 @@ contract Defaults is Constants { }); } - function createWithRange() public view returns (LockupLinear.CreateWithRange memory) { - return LockupLinear.CreateWithRange({ + function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { + return LockupLinear.CreateWithTimestamps({ sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, From b548695bc105395b4d31d21d4cc8bcfa747e0a83 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 22 Jan 2024 14:48:34 +0200 Subject: [PATCH 039/132] refactor: rename milestone to timestamp refactor: rename delta to duration --- script/Init.s.sol | 8 ++- src/SablierV2LockupDynamic.sol | 28 ++++---- src/interfaces/ISablierV2LockupDynamic.sol | 14 ++-- src/libraries/Errors.sol | 12 ++-- src/libraries/Helpers.sol | 66 ++++++++--------- src/types/DataTypes.sol | 16 ++--- test/fork/LockupDynamic.t.sol | 8 +-- .../createWithDurations.t.sol | 71 ++++++++++--------- .../createWithDurations.tree | 12 ++-- .../createWithTimestamps.t.sol | 62 ++++++++-------- .../createWithTimestamps.tree | 10 +-- .../streamed-amount-of/streamedAmountOf.t.sol | 10 +-- .../streamed-amount-of/streamedAmountOf.tree | 4 +- .../lockup-dynamic/createWithDurations.t.sol | 20 +++--- .../lockup-dynamic/createWithTimestamps.t.sol | 38 +++++----- .../lockup-dynamic/streamedAmountOf.t.sol | 24 +++---- .../fuzz/lockup-dynamic/withdraw.t.sol | 6 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 16 ++--- .../lockup-dynamic/createWithDurations.t.sol | 4 +- .../lockup-dynamic/createWithTimestamps.t.sol | 4 +- .../shared/lockup-linear/LockupLinear.t.sol | 9 +-- test/invariant/LockupDynamic.t.sol | 10 +-- .../handlers/LockupDynamicCreateHandler.sol | 8 +-- test/utils/Calculations.sol | 24 +++---- test/utils/Defaults.sol | 30 ++++---- test/utils/Fuzzers.sol | 68 +++++++++--------- test/utils/Utils.sol | 16 ++--- 27 files changed, 302 insertions(+), 296 deletions(-) diff --git a/script/Init.s.sol b/script/Init.s.sol index 3979c9bee..cf71876a2 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -78,9 +78,11 @@ contract Init is BaseScript { //////////////////////////////////////////////////////////////////////////*/ // Create the default lockupDynamic stream. - LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](2); - segments[0] = LockupDynamic.SegmentWithDelta({ amount: 2500e18, exponent: ud2x18(3.14e18), delta: 1 hours }); - segments[1] = LockupDynamic.SegmentWithDelta({ amount: 7500e18, exponent: ud2x18(0.5e18), delta: 1 weeks }); + LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](2); + segments[0] = + LockupDynamic.SegmentWithDuration({ amount: 2500e18, exponent: ud2x18(3.14e18), duration: 1 hours }); + segments[1] = + LockupDynamic.SegmentWithDuration({ amount: 7500e18, exponent: ud2x18(0.5e18), duration: 1 weeks }); lockupDynamic.createWithDurations( LockupDynamic.CreateWithDurations({ sender: sender, diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 060b5aa9c..e44d6113b 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -273,8 +273,8 @@ contract SablierV2LockupDynamic is noDelegateCall returns (uint256 streamId) { - // Checks: check the deltas and generate the canonical segments. - LockupDynamic.Segment[] memory segments = Helpers.checkDeltasAndCalculateMilestones(params.segments); + // Checks: check the durations and generate the canonical segments. + LockupDynamic.Segment[] memory segments = Helpers.checkDurationsAndCalculateTimestamps(params.segments); // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( @@ -345,32 +345,32 @@ contract SablierV2LockupDynamic is // Sum the amounts in all segments that precede the current time. uint128 previousSegmentAmounts; - uint40 currentSegmentMilestone = stream.segments[0].milestone; + uint40 currentSegmentTimestamp = stream.segments[0].timestamp; uint256 index = 0; - while (currentSegmentMilestone < currentTime) { + while (currentSegmentTimestamp < currentTime) { previousSegmentAmounts += stream.segments[index].amount; index += 1; - currentSegmentMilestone = stream.segments[index].milestone; + currentSegmentTimestamp = stream.segments[index].timestamp; } // After exiting the loop, the current segment is at `index`. SD59x18 currentSegmentAmount = stream.segments[index].amount.intoSD59x18(); SD59x18 currentSegmentExponent = stream.segments[index].exponent.intoSD59x18(); - currentSegmentMilestone = stream.segments[index].milestone; + currentSegmentTimestamp = stream.segments[index].timestamp; - uint40 previousMilestone; + uint40 previousTimestamp; if (index > 0) { // When the current segment's index is greater than or equal to 1, it implies that the segment is not - // the first. In this case, use the previous segment's milestone. - previousMilestone = stream.segments[index - 1].milestone; + // the first. In this case, use the previous segment's timestamp. + previousTimestamp = stream.segments[index - 1].timestamp; } else { - // Otherwise, the current segment is the first, so use the start time as the previous milestone. - previousMilestone = stream.startTime; + // Otherwise, the current segment is the first, so use the start time as the previous timestamp. + previousTimestamp = stream.startTime; } // Calculate how much time has passed since the segment started, and the total time of the segment. - SD59x18 elapsedSegmentTime = (currentTime - previousMilestone).intoSD59x18(); - SD59x18 totalSegmentTime = (currentSegmentMilestone - previousMilestone).intoSD59x18(); + SD59x18 elapsedSegmentTime = (currentTime - previousTimestamp).intoSD59x18(); + SD59x18 totalSegmentTime = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); // Divide the elapsed segment time by the total duration of the segment. SD59x18 elapsedSegmentTimePercentage = elapsedSegmentTime.div(totalSegmentTime); @@ -567,7 +567,7 @@ contract SablierV2LockupDynamic is unchecked { // The segment count cannot be zero at this point. uint256 segmentCount = params.segments.length; - stream.endTime = params.segments[segmentCount - 1].milestone; + stream.endTime = params.segments[segmentCount - 1].timestamp; stream.startTime = params.startTime; // Effects: store the segments. Since Solidity lacks a syntax for copying arrays directly from diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index bf030bd99..8f646cec3 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -92,8 +92,8 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { //////////////////////////////////////////////////////////////////////////*/ /// @notice Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of - /// `block.timestamp` and all specified time deltas. The segment milestones are derived from these - /// deltas. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. + /// `block.timestamp` and all specified time durations. The segment timestamps are derived from these + /// durations. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. /// /// @dev Emits a {Transfer} and {CreateLockupDynamicStream} event. /// @@ -106,13 +106,13 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { external returns (uint256 streamId); - /// @notice Creates a stream with the provided segment milestones, implying the end time from the last milestone. + /// @notice Creates a stream with the provided segment timestamps, implying the end time from the last timestamp. /// The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. /// /// @dev Emits a {Transfer} and {CreateLockupDynamicStream} event. /// /// Notes: - /// - As long as the segment milestones are arranged in ascending order, it is not an error for some + /// - As long as the segment timestamps are arranged in ascending order, it is not an error for some /// of them to be in the past. /// /// Requirements: @@ -120,9 +120,9 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`. - /// - `params.startTime` must be less than the first segment's milestone. - /// - The segment milestones must be arranged in ascending order. - /// - The last segment milestone (i.e. the stream's end time) must be in the future. + /// - `params.startTime` must be less than the first segment's timestamp. + /// - The segment timestamps must be arranged in ascending order. + /// - The last segment timestamp (i.e. the stream's end time) must be in the future. /// - The sum of the segment amounts must equal the deposit amount. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index d410a9255..278c43f8b 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -97,15 +97,15 @@ library Errors { /// @notice Thrown when trying to create a stream with no segments. error SablierV2LockupDynamic_SegmentCountZero(); - /// @notice Thrown when trying to create a stream with unordered segment milestones. - error SablierV2LockupDynamic_SegmentMilestonesNotOrdered( - uint256 index, uint40 previousMilestone, uint40 currentMilestone + /// @notice Thrown when trying to create a stream with unordered segment timestampts. + error SablierV2LockupDynamic_SegmentTimestampsNotOrdered( + uint256 index, uint40 previousTimestamp, uint40 currentTimestamp ); /// @notice Thrown when trying to create a stream with a start time not strictly less than the first - /// segment milestone. - error SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone( - uint40 startTime, uint40 firstSegmentMilestone + /// segment timestamp. + error SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( + uint40 startTime, uint40 firstSegmentTimestamp ); /*////////////////////////////////////////////////////////////////////////// diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 319cc28b9..73ee41f34 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -109,34 +109,34 @@ library Helpers { } } - /// @dev Checks that the segment array counts match, and then adjusts the segments by calculating the milestones. - function checkDeltasAndCalculateMilestones(LockupDynamic.SegmentWithDelta[] memory segments) + /// @dev Checks that the segment array counts match, and then adjusts the segments by calculating the timestamps. + function checkDurationsAndCalculateTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) internal view - returns (LockupDynamic.Segment[] memory segmentsWithMilestones) + returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) { uint256 segmentCount = segments.length; - segmentsWithMilestones = new LockupDynamic.Segment[](segmentCount); + segmentsWithTimestamps = new LockupDynamic.Segment[](segmentCount); // Make the current time the stream's start time. uint40 startTime = uint40(block.timestamp); - // It is safe to use unchecked arithmetic because {_createWithMilestone} will nonetheless check the soundness - // of the calculated segment milestones. + // It is safe to use unchecked arithmetic because {_createWithTimestamps} will nonetheless check the soundness + // of the calculated segment timestamps. unchecked { - // Precompute the first segment because of the need to add the start time to the first segment delta. - segmentsWithMilestones[0] = LockupDynamic.Segment({ + // Precompute the first segment because of the need to add the start time to the first segment duration. + segmentsWithTimestamps[0] = LockupDynamic.Segment({ amount: segments[0].amount, exponent: segments[0].exponent, - milestone: startTime + segments[0].delta + timestamp: startTime + segments[0].duration }); - // Copy the segment amounts and exponents, and calculate the segment milestones. + // Copy the segment amounts and exponents, and calculate the segment timestamps. for (uint256 i = 1; i < segmentCount; ++i) { - segmentsWithMilestones[i] = LockupDynamic.Segment({ + segmentsWithTimestamps[i] = LockupDynamic.Segment({ amount: segments[i].amount, exponent: segments[i].exponent, - milestone: segmentsWithMilestones[i - 1].milestone + segments[i].delta + timestamp: segmentsWithTimestamps[i - 1].timestamp + segments[i].duration }); } } @@ -148,9 +148,9 @@ library Helpers { /// @dev Checks that: /// - /// 1. The first milestone is strictly greater than the start time. - /// 2. The milestones are ordered chronologically. - /// 3. There are no duplicate milestones. + /// 1. The first timestamp is strictly greater than the start time. + /// 2. The timestamps are ordered chronologically. + /// 3. There are no duplicate timestamps. /// 4. The deposit amount is equal to the sum of all segment amounts. function _checkSegments( LockupDynamic.Segment[] memory segments, @@ -160,44 +160,44 @@ library Helpers { private view { - // Checks: the start time is strictly less than the first segment milestone. - if (startTime >= segments[0].milestone) { - revert Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone( - startTime, segments[0].milestone + // Checks: the start time is strictly less than the first segment timestamp. + if (startTime >= segments[0].timestamp) { + revert Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( + startTime, segments[0].timestamp ); } // Pre-declare the variables needed in the for loop. uint128 segmentAmountsSum; - uint40 currentMilestone; - uint40 previousMilestone; + uint40 currentTimestamp; + uint40 previousTimestamp; // Iterate over the segments to: // // 1. Calculate the sum of all segment amounts. - // 2. Check that the milestones are ordered. + // 2. Check that the timestamps are ordered. uint256 count = segments.length; for (uint256 index = 0; index < count; ++index) { // Add the current segment amount to the sum. segmentAmountsSum += segments[index].amount; - // Checks: the current milestone is strictly greater than the previous milestone. - currentMilestone = segments[index].milestone; - if (currentMilestone <= previousMilestone) { - revert Errors.SablierV2LockupDynamic_SegmentMilestonesNotOrdered( - index, previousMilestone, currentMilestone + // Checks: the current timestamp is strictly greater than the previous timestamp. + currentTimestamp = segments[index].timestamp; + if (currentTimestamp <= previousTimestamp) { + revert Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered( + index, previousTimestamp, currentTimestamp ); } - // Make the current milestone the previous milestone of the next loop iteration. - previousMilestone = currentMilestone; + // Make the current timestamp the previous timestamp of the next loop iteration. + previousTimestamp = currentTimestamp; } - // Checks: the last milestone is in the future. - // When the loop exits, the current milestone is the last milestone, i.e. the stream's end time. + // Checks: the last timestamp is in the future. + // When the loop exits, the current timestamp is the last timestamp, i.e. the stream's end time. uint40 currentTime = uint40(block.timestamp); - if (currentTime >= currentMilestone) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, currentMilestone); + if (currentTime >= currentTimestamp) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, currentTimestamp); } // Checks: the deposit amount is equal to the segment amounts sum. diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 1a9337a04..543e8de4e 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -79,8 +79,8 @@ library LockupDynamic { /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param segments Segments with deltas used to compose the custom streaming curve. Milestones are calculated by - /// starting from `block.timestamp` and adding each delta to the previous milestone. + /// @param segments Segments with durations used to compose the custom streaming curve. Timestamps are calculated by + /// starting from `block.timestamp` and adding each duration to the previous timestamp. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { @@ -90,7 +90,7 @@ library LockupDynamic { IERC20 asset; bool cancelable; bool transferable; - SegmentWithDelta[] segments; + SegmentWithDuration[] segments; Broker broker; } @@ -131,22 +131,22 @@ library LockupDynamic { /// @notice Segment struct used in the Lockup Dynamic stream. /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals. /// @param exponent The exponent of this segment, denoted as a fixed-point number. - /// @param milestone The Unix timestamp indicating this segment's end. + /// @param timestamp The Unix timestamp indicating this segment's end. struct Segment { // slot 0 uint128 amount; UD2x18 exponent; - uint40 milestone; + uint40 timestamp; } /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDurations}. /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals. /// @param exponent The exponent of this segment, denoted as a fixed-point number. - /// @param delta The time difference in seconds between this segment and the previous one. - struct SegmentWithDelta { + /// @param duration The time difference in seconds between this segment and the previous one. + struct SegmentWithDuration { uint128 amount; UD2x18 exponent; - uint40 delta; + uint40 duration; } /// @notice Lockup Dynamic stream. diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 4e7b0c2de..931e565a0 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -109,7 +109,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { /// - Start time in the past /// - Start time in the present /// - Start time in the future - /// - Start time equal and not equal to the first segment milestone + /// - Start time equal and not equal to the first segment timestamp /// - Multiple values for the broker fee, including zero /// - Multiple values for the protocol fee, including zero /// - Multiple values for the withdraw amount, including zero @@ -122,8 +122,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); params.transferable = true; - // Fuzz the segment milestones. - fuzzSegmentMilestones(params.segments, params.startTime); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(params.segments, params.startTime); // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). Vars memory vars; @@ -156,7 +156,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vars.streamId = lockupDynamic.nextStreamId(); vars.range = - LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].milestone }); + LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index aeac29e30..bf8b3823c 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -34,81 +34,84 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_LoopCalculationOverflowsBlockGasLimit() external whenNotDelegateCalled { - LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](250_000); + LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](250_000); vm.expectRevert(bytes("")); - createDefaultStreamWithDeltas(segments); + createDefaultStreamWithDurations(segments); } - function test_RevertWhen_DeltasZero() + function test_RevertWhen_DurationsZero() external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDurationsLD().segments; - segments[1].delta = 0; + LockupDynamic.SegmentWithDuration[] memory segments = defaults.createWithDurationsLD().segments; + segments[1].duration = 0; uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentMilestonesNotOrdered.selector, + Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, index, - startTime + segments[0].delta, - startTime + segments[0].delta + startTime + segments[0].duration, + startTime + segments[0].duration ) ); - createDefaultStreamWithDeltas(segments); + createDefaultStreamWithDurations(segments); } - function test_RevertWhen_MilestonesCalculationsOverflows_StartTimeNotLessThanFirstSegmentMilestone() + function test_RevertWhen_TimestampsCalculationsOverflows_StartTimeNotLessThanFirstSegmentTimestamp() external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit - whenDeltasNotZero + whenDurationsNotZero { unchecked { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDelta[] memory segments = defaults.createWithDurationsLD().segments; - segments[0].delta = MAX_UINT40; + LockupDynamic.SegmentWithDuration[] memory segments = defaults.createWithDurationsLD().segments; + segments[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone.selector, + Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, startTime, - startTime + segments[0].delta + startTime + segments[0].duration ) ); - createDefaultStreamWithDeltas(segments); + createDefaultStreamWithDurations(segments); } } - function test_RevertWhen_MilestonesCalculationsOverflows_SegmentMilestonesNotOrdered() + function test_RevertWhen_TimestampsCalculationsOverflows_SegmentTimestampsNotOrdered() external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit - whenDeltasNotZero + whenDurationsNotZero { unchecked { uint40 startTime = getBlockTimestamp(); - // Create new segments that overflow when the milestones are eventually calculated. - LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](2); - segments[0] = - LockupDynamic.SegmentWithDelta({ amount: 0, exponent: ud2x18(1e18), delta: startTime + 1 seconds }); - segments[1] = defaults.segmentsWithDeltas()[0]; - segments[1].delta = MAX_UINT40; + // Create new segments that overflow when the timestamps are eventually calculated. + LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](2); + segments[0] = LockupDynamic.SegmentWithDuration({ + amount: 0, + exponent: ud2x18(1e18), + duration: startTime + 1 seconds + }); + segments[1] = defaults.segmentsWithDurations()[0]; + segments[1].duration = MAX_UINT40; // Expect the relevant error to be thrown. uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentMilestonesNotOrdered.selector, + Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, index, - startTime + segments[0].delta, - startTime + segments[0].delta + segments[1].delta + startTime + segments[0].duration, + startTime + segments[0].duration + segments[1].duration ) ); // Create the stream. - createDefaultStreamWithDeltas(segments); + createDefaultStreamWithDurations(segments); } } @@ -116,8 +119,8 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit - whenDeltasNotZero - whenMilestonesCalculationsDoNotOverflow + whenDurationsNotZero + whenTimestampsCalculationsDoNotOverflow { // Make the Sender the stream's funder address funder = users.sender; @@ -131,10 +134,10 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDynamic.Range({ start: currentTime, end: currentTime + defaults.TOTAL_DURATION() }); // Adjust the segments. - LockupDynamic.SegmentWithDelta[] memory segmentsWithDeltas = defaults.segmentsWithDeltas(); + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].milestone = range.start + segmentsWithDeltas[0].delta; - segments[1].milestone = segments[0].milestone + segmentsWithDeltas[1].delta; + segments[0].timestamp = range.start + segmentsWithDurations[0].duration; + segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. expectCallToTransferFrom({ @@ -165,7 +168,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is }); // Create the stream. - createDefaultStreamWithDeltas(); + createDefaultStreamWithDurations(); // Assert that the stream has been created. LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree index e3a5c988a..e1fa7ae20 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree @@ -5,15 +5,15 @@ createWithDurations.t.sol ├── when the loop calculations overflow the block gas limit │ └── it should revert └── when the loop calculations do not overflow the block gas limit - ├── when at least one of the deltas at index one or greater is zero + ├── when at least one of the durations at index one or greater is zero │ └── it should revert - └── when none of the deltas is zero - ├── when the segment milestone calculations overflow uint256 - │ ├── when the start time is not less than the first segment milestone + └── when none of the durations is zero + ├── when the segment timestamp calculations overflow uint256 + │ ├── when the start time is not less than the first segment timestamp │ │ └── it should revert - │ └── when the segment milestones are not ordered + │ └── when the segment timestamps are not ordered │ └── it should revert - └── when the segment milestone calculations do not overflow uint256 + └── when the segment timestamp calculations do not overflow uint256 ├── it should create the stream ├── it should bump the next stream id ├── it should record the protocol fee diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index b39b7251a..f7842897b 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -87,7 +87,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithSegments(segments); } - function test_RevertWhen_StartTimeGreaterThanFirstSegmentMilestone() + function test_RevertWhen_StartTimeGreaterThanFirstSegmentTimestamp() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -96,16 +96,16 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow { - // Change the milestone of the first segment. + // Change the timestamp of the first segment. LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].milestone = defaults.START_TIME() - 1 seconds; + segments[0].timestamp = defaults.START_TIME() - 1 seconds; // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone.selector, + Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), - segments[0].milestone + segments[0].timestamp ) ); @@ -113,7 +113,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithSegments(segments); } - function test_RevertWhen_StartTimeEqualToFirstSegmentMilestone() + function test_RevertWhen_StartTimeEqualToFirstSegmentTimestamp() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -122,16 +122,16 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow { - // Change the milestone of the first segment. + // Change the timestamp of the first segment. LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].milestone = defaults.START_TIME(); + segments[0].timestamp = defaults.START_TIME(); // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone.selector, + Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), - segments[0].milestone + segments[0].timestamp ) ); @@ -139,7 +139,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithSegments(segments); } - function test_RevertWhen_SegmentMilestonesNotOrdered() + function test_RevertWhen_SegmentTimestampsNotOrdered() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -147,20 +147,20 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone + whenStartTimeLessThanFirstSegmentTimestamp { - // Swap the segment milestones. + // Swap the segment timestamps. LockupDynamic.Segment[] memory segments = defaults.segments(); - (segments[0].milestone, segments[1].milestone) = (segments[1].milestone, segments[0].milestone); + (segments[0].timestamp, segments[1].timestamp) = (segments[1].timestamp, segments[0].timestamp); // Expect the relevant error to be thrown. uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentMilestonesNotOrdered.selector, + Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, index, - segments[0].milestone, - segments[1].milestone + segments[0].timestamp, + segments[1].timestamp ) ); @@ -176,8 +176,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered { uint40 endTime = defaults.END_TIME(); vm.warp({ timestamp: endTime }); @@ -193,8 +193,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture { // Disable both the protocol and the broker fee so that they don't interfere with the calculations. @@ -233,8 +233,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum { @@ -260,8 +260,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh @@ -279,8 +279,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh @@ -307,8 +307,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh @@ -326,8 +326,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index 6debf4ca6..ee1418596 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -17,14 +17,14 @@ createWithTimestamps.t.sol ├── when the segment amounts sum overflows │ └── it should revert └── when the segment amounts sum does not overflow - ├── when the start time is greater than the first segment milestone + ├── when the start time is greater than the first segment timestamp │ └── it should revert - ├── when the start time is equal to the first segment milestone + ├── when the start time is equal to the first segment timestamp │ └── it should revert - └── when the start time is less than the first segment milestone - ├── when the segment milestones are not ordered + └── when the start time is less than the first segment timestamp + ├── when the segment timestamps are not ordered │ └── it should revert - └── when the segment milestones are ordered + └── when the segment timestamps are ordered ├── when the end time is not in the future │ └── it should revert └── when the end time is in the future diff --git a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol index 040dd310b..f1d8ab14f 100644 --- a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol @@ -58,7 +58,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Concrete_Test is segments[0] = LockupDynamic.Segment({ amount: defaults.DEPOSIT_AMOUNT(), exponent: defaults.segments()[1].exponent, - milestone: defaults.END_TIME() + timestamp: defaults.END_TIME() }); // Create the stream. @@ -74,7 +74,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Concrete_Test is _; } - function test_StreamedAmountOf_CurrentMilestone1st() + function test_StreamedAmountOf_CurrentTimestamp1st() external givenNotNull givenStreamHasNotBeenCanceled @@ -91,18 +91,18 @@ contract StreamedAmountOf_LockupDynamic_Integration_Concrete_Test is assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } - modifier givenCurrentMilestoneNot1st() { + modifier givenCurrentTimestampNot1st() { _; } - function test_StreamedAmountOf_CurrentMilestoneNot1st() + function test_StreamedAmountOf_CurrentTimestampNot1st() external givenNotNull givenStreamHasNotBeenCanceled givenStatusStreaming whenStartTimeInThePast givenMultipleSegments - givenCurrentMilestoneNot1st + givenCurrentTimestampNot1st { // Simulate the passage of time. 750 seconds is ~10% of the way in the second segment. vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 750 seconds }); diff --git a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree index 50815136d..8a231f4a0 100644 --- a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree +++ b/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree @@ -8,7 +8,7 @@ streamedAmountOf.t.sol ├── given there is one segment │ └── it should return the correct streamed amount └── given there are multiple segments - ├── given the current milestone is the 1st in the array + ├── given the current timestamp is the 1st in the array │ └── it should return the correct streamed amount - └── given the current milestone is not the 1st in the array + └── given the current timestamp is not the 1st in the array └── it should return the correct streamed amount diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 81d7ca19c..4285a8034 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -33,22 +33,22 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is uint128 initialProtocolRevenues; bool isCancelable; bool isSettled; - LockupDynamic.Segment[] segmentsWithMilestones; + LockupDynamic.Segment[] segmentsWithTimestamps; uint128 totalAmount; } - function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDelta[] memory segments) + function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) external whenNotDelegateCalled whenLoopCalculationsDoNotOverflowBlockGasLimit - whenDeltasNotZero - whenMilestonesCalculationsDoNotOverflow + whenDurationsNotZero + whenTimestampsCalculationsDoNotOverflow { vm.assume(segments.length != 0); - // Fuzz the deltas. + // Fuzz the durations. Vars memory vars; - fuzzSegmentDeltas(segments); + fuzzSegmentDurations(segments); // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(segments); @@ -75,10 +75,10 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is } // Create the range struct. - vars.segmentsWithMilestones = getSegmentsWithMilestones(segments); + vars.segmentsWithTimestamps = getSegmentsWithTimestamps(segments); LockupDynamic.Range memory range = LockupDynamic.Range({ start: getBlockTimestamp(), - end: vars.segmentsWithMilestones[vars.segmentsWithMilestones.length - 1].milestone + end: vars.segmentsWithTimestamps[vars.segmentsWithTimestamps.length - 1].timestamp }); // Expect the relevant event to be emitted. @@ -92,7 +92,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is asset: dai, cancelable: true, transferable: true, - segments: vars.segmentsWithMilestones, + segments: vars.segmentsWithTimestamps, range: range, broker: users.broker }); @@ -118,7 +118,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.segments, vars.segmentsWithMilestones, "segments"); + assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); assertEq(actualStream.startTime, range.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 0bf50c093..16909789f 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -58,7 +58,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is createDefaultStreamWithSegments(segments); } - function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentMilestone(uint40 firstMilestone) + function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentTimestamp(uint40 firstTimestamp) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -67,18 +67,18 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow { - firstMilestone = boundUint40(firstMilestone, 0, defaults.START_TIME()); + firstTimestamp = boundUint40(firstTimestamp, 0, defaults.START_TIME()); - // Change the milestone of the first segment. + // Change the timestamp of the first segment. LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].milestone = firstMilestone; + segments[0].timestamp = firstTimestamp; // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentMilestone.selector, + Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), - segments[0].milestone + segments[0].timestamp ) ); @@ -94,8 +94,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); @@ -136,8 +136,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum { @@ -163,8 +163,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh @@ -193,12 +193,12 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - All possible permutations for the funder, sender, recipient, and broker - /// - Multiple values for the segment amounts, exponents, and milestones + /// - Multiple values for the segment amounts, exponents, and timestamps /// - Cancelable and not cancelable /// - Start time in the past /// - Start time in the present /// - Start time in the future - /// - Start time equal and not equal to the first segment milestone + /// - Start time equal and not equal to the first segment timestamp /// - Multiple values for the broker fee, including zero /// - Multiple values for the protocol fee, including zero function testFuzz_CreateWithTimestamps( @@ -213,8 +213,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentMilestone - whenSegmentMilestonesOrdered + whenStartTimeLessThanFirstSegmentTimestamp + whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum givenProtocolFeeNotTooHigh @@ -229,8 +229,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); params.transferable = true; - // Fuzz the segment milestones. - fuzzSegmentMilestones(params.segments, params.startTime); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(params.segments, params.startTime); // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). Vars memory vars; @@ -269,7 +269,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); LockupDynamic.Range memory range = - LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].milestone }); + LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); emit CreateLockupDynamicStream({ streamId: streamId, funder: funder, diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 567b8f587..a0068d4e8 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -42,7 +42,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is whenStartTimeInThePast { vm.assume(segment.amount != 0); - segment.milestone = boundUint40(segment.milestone, defaults.CLIFF_TIME(), defaults.END_TIME()); + segment.timestamp = boundUint40(segment.timestamp, defaults.CLIFF_TIME(), defaults.END_TIME()); timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); // Create the single-segment array. @@ -73,7 +73,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is _; } - modifier whenCurrentMilestoneNot1st() { + modifier whenCurrentTimestampNot1st() { _; } @@ -94,12 +94,12 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is givenStreamHasNotBeenCanceled whenStartTimeInThePast givenMultipleSegments - whenCurrentMilestoneNot1st + whenCurrentTimestampNot1st { vm.assume(segments.length > 1); - // Fuzz the segment milestones. - fuzzSegmentMilestones(segments, defaults.START_TIME()); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(segments, defaults.START_TIME()); // Fuzz the segment amounts. (uint128 totalAmount,) = fuzzDynamicStreamAmounts({ @@ -110,8 +110,8 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is }); // Bound the time jump. - uint40 firstSegmentDuration = segments[1].milestone - segments[0].milestone; - uint40 totalDuration = segments[segments.length - 1].milestone - defaults.START_TIME(); + uint40 firstSegmentDuration = segments[1].timestamp - segments[0].timestamp; + uint40 totalDuration = segments[segments.length - 1].timestamp - defaults.START_TIME(); timeJump = boundUint40(timeJump, firstSegmentDuration, totalDuration + 100 seconds); // Mint enough assets to the Sender. @@ -145,12 +145,12 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is givenStreamHasNotBeenCanceled whenStartTimeInThePast givenMultipleSegments - whenCurrentMilestoneNot1st + whenCurrentTimestampNot1st { vm.assume(segments.length > 1); - // Fuzz the segment milestones. - fuzzSegmentMilestones(segments, defaults.START_TIME()); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(segments, defaults.START_TIME()); // Fuzz the segment amounts. (uint128 totalAmount,) = fuzzDynamicStreamAmounts({ @@ -161,8 +161,8 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is }); // Bound the time warps. - uint40 firstSegmentDuration = segments[1].milestone - segments[0].milestone; - uint40 totalDuration = segments[segments.length - 1].milestone - defaults.START_TIME(); + uint40 firstSegmentDuration = segments[1].timestamp - segments[0].timestamp; + uint40 totalDuration = segments[segments.length - 1].timestamp - defaults.START_TIME(); timeWarp0 = boundUint40(timeWarp0, firstSegmentDuration, totalDuration - 1); timeWarp1 = boundUint40(timeWarp1, timeWarp0, totalDuration); diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index d88c7be2c..564039809 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -55,14 +55,14 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is Vars memory vars; vars.funder = users.sender; - // Fuzz the segment milestones. - fuzzSegmentMilestones(params.segments, defaults.START_TIME()); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(params.segments, defaults.START_TIME()); // Fuzz the segment amounts. (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(params.segments); // Bound the time jump. - vars.totalDuration = params.segments[params.segments.length - 1].milestone - defaults.START_TIME(); + vars.totalDuration = params.segments[params.segments.length - 1].timestamp - defaults.START_TIME(); params.timeJump = _bound(params.timeJump, 1 seconds, vars.totalDuration + 100 seconds); // Mint enough assets to the funder. diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 046b1af22..b67bf3aa4 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -39,10 +39,10 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh _params.createWithTimestamps.broker = defaults.broker(); // See https://github.com/ethereum/solidity/issues/12783 - LockupDynamic.SegmentWithDelta[] memory segmentsWithDeltas = defaults.segmentsWithDeltas(); + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); LockupDynamic.Segment[] memory segments = defaults.segments(); for (uint256 i = 0; i < defaults.SEGMENT_COUNT(); ++i) { - _params.createWithDurations.segments.push(segmentsWithDeltas[i]); + _params.createWithDurations.segments.push(segmentsWithDurations[i]); _params.createWithTimestamps.segments.push(segments[i]); } } @@ -66,13 +66,13 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with deltas. - function createDefaultStreamWithDeltas() internal returns (uint256 streamId) { + /// @dev Creates the default stream with durations. + function createDefaultStreamWithDurations() internal returns (uint256 streamId) { streamId = lockupDynamic.createWithDurations(_params.createWithDurations); } - /// @dev Creates the default stream with the provided deltas. - function createDefaultStreamWithDeltas(LockupDynamic.SegmentWithDelta[] memory segments) + /// @dev Creates the default stream with the provided durations. + function createDefaultStreamWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) internal returns (uint256 streamId) { @@ -84,7 +84,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh /// @dev Creates the default stream with the provided end time. function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.segments[1].milestone = endTime; + params.segments[1].timestamp = endTime; streamId = lockupDynamic.createWithTimestamps(params); } @@ -106,7 +106,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh function createDefaultStreamWithRange(LockupDynamic.Range memory range) internal returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.startTime = range.start; - params.segments[1].milestone = range.end; + params.segments[1].timestamp = range.end; streamId = lockupDynamic.createWithTimestamps(params); } diff --git a/test/integration/shared/lockup-dynamic/createWithDurations.t.sol b/test/integration/shared/lockup-dynamic/createWithDurations.t.sol index b9687b7a1..31460ec2b 100644 --- a/test/integration/shared/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithDurations.t.sol @@ -18,11 +18,11 @@ contract CreateWithDurations_Integration_Shared_Test is LockupDynamic_Integratio _; } - modifier whenDeltasNotZero() { + modifier whenDurationsNotZero() { _; } - modifier whenMilestonesCalculationsDoNotOverflow() { + modifier whenTimestampsCalculationsDoNotOverflow() { _; } } diff --git a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol index 3027fdb8e..574f79390 100644 --- a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol @@ -34,11 +34,11 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupDynamic_Integrati _; } - modifier whenStartTimeLessThanFirstSegmentMilestone() { + modifier whenStartTimeLessThanFirstSegmentTimestamp() { _; } - modifier whenSegmentMilestonesOrdered() { + modifier whenSegmentTimestampsOrdered() { _; } diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 87315c0fa..1fe86adbf 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -79,13 +79,10 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided createWithTimestamps. - function createDefaultStreamWithRange(LockupLinear.Range memory createWithTimestamps) - internal - returns (uint256 streamId) - { + /// @dev Creates the default stream with the provided range. + function createDefaultStreamWithRange(LockupLinear.Range memory range) internal returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.range = createWithTimestamps; + params.range = range; streamId = lockupLinear.createWithTimestamps(params); } diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index 31e3c0a57..811db9f30 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -79,16 +79,16 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { } } - /// @dev Unordered segment milestones are not allowed. - function invariant_SegmentMilestonesOrdered() external useCurrentTimestamp { + /// @dev Unordered segment timestamps are not allowed. + function invariant_SegmentTimestampsOrdered() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); LockupDynamic.Segment[] memory segments = lockupDynamic.getSegments(streamId); - uint40 previousMilestone = segments[0].milestone; + uint40 previousTimestamp = segments[0].timestamp; for (uint256 j = 1; j < segments.length; ++j) { - assertGt(segments[j].milestone, previousMilestone, "Invariant violated: segment milestones not ordered"); - previousMilestone = segments[j].milestone; + assertGt(segments[j].timestamp, previousTimestamp, "Invariant violated: segment timestamps not ordered"); + previousTimestamp = segments[j].timestamp; } } } diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 67af327ed..41eb5d3cf 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -68,8 +68,8 @@ contract LockupDynamicCreateHandler is BaseHandler { // Bound the broker fee. params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - // Fuzz the deltas. - fuzzSegmentDeltas(params.segments); + // Fuzz the durations. + fuzzSegmentDurations(params.segments); // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). (params.totalAmount,) = fuzzDynamicStreamAmounts({ @@ -116,8 +116,8 @@ contract LockupDynamicCreateHandler is BaseHandler { params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); - // Fuzz the segment milestones. - fuzzSegmentMilestones(params.segments, params.startTime); + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(params.segments, params.startTime); // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). (params.totalAmount,) = fuzzDynamicStreamAmounts({ diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index f1f3ceae7..abbf8562c 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -55,33 +55,33 @@ abstract contract Calculations { view returns (uint128) { - if (currentTime >= segments[segments.length - 1].milestone) { + if (currentTime >= segments[segments.length - 1].timestamp) { return depositAmount; } unchecked { uint128 previousSegmentAmounts; - uint40 currentSegmentMilestone = segments[0].milestone; + uint40 currentSegmentTimestamp = segments[0].timestamp; uint256 index = 0; - while (currentSegmentMilestone < currentTime) { + while (currentSegmentTimestamp < currentTime) { previousSegmentAmounts += segments[index].amount; index += 1; - currentSegmentMilestone = segments[index].milestone; + currentSegmentTimestamp = segments[index].timestamp; } SD59x18 currentSegmentAmount = segments[index].amount.intoSD59x18(); SD59x18 currentSegmentExponent = segments[index].exponent.intoSD59x18(); - currentSegmentMilestone = segments[index].milestone; + currentSegmentTimestamp = segments[index].timestamp; - uint40 previousMilestone; + uint40 previousTimestamp; if (index > 0) { - previousMilestone = segments[index - 1].milestone; + previousTimestamp = segments[index - 1].timestamp; } else { - previousMilestone = defaults.START_TIME(); + previousTimestamp = defaults.START_TIME(); } - SD59x18 elapsedSegmentTime = (currentTime - previousMilestone).intoSD59x18(); - SD59x18 totalSegmentTime = (currentSegmentMilestone - previousMilestone).intoSD59x18(); + SD59x18 elapsedSegmentTime = (currentTime - previousTimestamp).intoSD59x18(); + SD59x18 totalSegmentTime = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); SD59x18 elapsedSegmentTimePercentage = elapsedSegmentTime.div(totalSegmentTime); SD59x18 multiplier = elapsedSegmentTimePercentage.pow(currentSegmentExponent); @@ -99,12 +99,12 @@ abstract contract Calculations { view returns (uint128) { - if (currentTime >= segment.milestone) { + if (currentTime >= segment.timestamp) { return segment.amount; } unchecked { SD59x18 elapsedTime = (currentTime - defaults.START_TIME()).intoSD59x18(); - SD59x18 totalTime = (segment.milestone - defaults.START_TIME()).intoSD59x18(); + SD59x18 totalTime = (segment.timestamp - defaults.START_TIME()).intoSD59x18(); SD59x18 elapsedTimePercentage = elapsedTime.div(totalTime); SD59x18 multiplier = elapsedTimePercentage.pow(segment.exponent.intoSD59x18()); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 73af3e950..36bbe5faf 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -135,14 +135,14 @@ contract Defaults is Constants { uint128 amount = DEPOSIT_AMOUNT / uint128(MAX_SEGMENT_COUNT); UD2x18 exponent = ud2x18(2.71e18); - // Generate a bunch of segments with the same amount, same exponent, and with milestones evenly spread apart. + // Generate a bunch of segments with the same amount, same exponent, and with timestamps evenly spread apart. maxSegments_ = new LockupDynamic.Segment[](MAX_SEGMENT_COUNT); for (uint40 i = 0; i < MAX_SEGMENT_COUNT; ++i) { maxSegments_[i] = ( LockupDynamic.Segment({ amount: amount, exponent: exponent, - milestone: START_TIME + MAX_SEGMENT_DURATION * (i + 1) + timestamp: START_TIME + MAX_SEGMENT_DURATION * (i + 1) }) ); } @@ -151,28 +151,32 @@ contract Defaults is Constants { function segments() public view returns (LockupDynamic.Segment[] memory segments_) { segments_ = new LockupDynamic.Segment[](2); segments_[0] = ( - LockupDynamic.Segment({ amount: 2500e18, exponent: ud2x18(3.14e18), milestone: START_TIME + CLIFF_DURATION }) + LockupDynamic.Segment({ amount: 2500e18, exponent: ud2x18(3.14e18), timestamp: START_TIME + CLIFF_DURATION }) ); segments_[1] = ( - LockupDynamic.Segment({ amount: 7500e18, exponent: ud2x18(0.5e18), milestone: START_TIME + TOTAL_DURATION }) + LockupDynamic.Segment({ amount: 7500e18, exponent: ud2x18(0.5e18), timestamp: START_TIME + TOTAL_DURATION }) ); } - function segmentsWithDeltas() public view returns (LockupDynamic.SegmentWithDelta[] memory segmentsWithDeltas_) { + function segmentsWithDurations() + public + view + returns (LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations_) + { LockupDynamic.Segment[] memory segments_ = segments(); - segmentsWithDeltas_ = new LockupDynamic.SegmentWithDelta[](2); - segmentsWithDeltas_[0] = ( - LockupDynamic.SegmentWithDelta({ + segmentsWithDurations_ = new LockupDynamic.SegmentWithDuration[](2); + segmentsWithDurations_[0] = ( + LockupDynamic.SegmentWithDuration({ amount: segments_[0].amount, exponent: segments_[0].exponent, - delta: 2500 seconds + duration: 2500 seconds }) ); - segmentsWithDeltas_[1] = ( - LockupDynamic.SegmentWithDelta({ + segmentsWithDurations_[1] = ( + LockupDynamic.SegmentWithDuration({ amount: segments_[1].amount, exponent: segments_[1].exponent, - delta: 7500 seconds + duration: 7500 seconds }) ); } @@ -189,7 +193,7 @@ contract Defaults is Constants { asset: asset, cancelable: true, transferable: true, - segments: segmentsWithDeltas(), + segments: segmentsWithDurations(), broker: broker() }); } diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index a42184ebd..dc61affb1 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -30,20 +30,20 @@ abstract contract Fuzzers is Constants, Utils { } /// @dev Just like {fuzzDynamicStreamAmounts} but with defaults. - function fuzzDynamicStreamAmounts(LockupDynamic.SegmentWithDelta[] memory segments) + function fuzzDynamicStreamAmounts(LockupDynamic.SegmentWithDuration[] memory segments) internal view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { - LockupDynamic.Segment[] memory segmentsWithMilestones = getSegmentsWithMilestones(segments); + LockupDynamic.Segment[] memory segmentsWithTimestamps = getSegmentsWithTimestamps(segments); (totalAmount, createAmounts) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, - segments: segmentsWithMilestones, + segments: segmentsWithTimestamps, protocolFee: defaults.PROTOCOL_FEE(), brokerFee: defaults.BROKER_FEE() }); - for (uint256 i = 0; i < segmentsWithMilestones.length; ++i) { - segments[i].amount = segmentsWithMilestones[i].amount; + for (uint256 i = 0; i < segmentsWithTimestamps.length; ++i) { + segments[i].amount = segmentsWithTimestamps[i].amount; } } @@ -51,7 +51,7 @@ abstract contract Fuzzers is Constants, Utils { /// fee). function fuzzDynamicStreamAmounts( uint128 upperBound, - LockupDynamic.SegmentWithDelta[] memory segments, + LockupDynamic.SegmentWithDuration[] memory segments, UD60x18 protocolFee, UD60x18 brokerFee ) @@ -59,11 +59,11 @@ abstract contract Fuzzers is Constants, Utils { view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { - LockupDynamic.Segment[] memory segmentsWithMilestones = getSegmentsWithMilestones(segments); + LockupDynamic.Segment[] memory segmentsWithTimestamps = getSegmentsWithTimestamps(segments); (totalAmount, createAmounts) = - fuzzDynamicStreamAmounts(upperBound, segmentsWithMilestones, protocolFee, brokerFee); - for (uint256 i = 0; i < segmentsWithMilestones.length; ++i) { - segments[i].amount = segmentsWithMilestones[i].amount; + fuzzDynamicStreamAmounts(upperBound, segmentsWithTimestamps, protocolFee, brokerFee); + for (uint256 i = 0; i < segmentsWithTimestamps.length; ++i) { + segments[i].amount = segmentsWithTimestamps[i].amount; } } @@ -115,47 +115,47 @@ abstract contract Fuzzers is Constants, Utils { segments[segments.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); } - /// @dev Fuzzes the deltas. - function fuzzSegmentDeltas(LockupDynamic.SegmentWithDelta[] memory segments) internal pure { + /// @dev Fuzzes the durations. + function fuzzSegmentDurations(LockupDynamic.SegmentWithDuration[] memory segments) internal pure { unchecked { - // Precompute the first segment delta. - segments[0].delta = uint40(_bound(segments[0].delta, 1, 100)); - - // Bound the deltas so that none is zero and the calculations don't overflow. - uint256 deltaCount = segments.length; - uint40 maxDelta = (MAX_UNIX_TIMESTAMP - segments[0].delta) / uint40(deltaCount); - for (uint256 i = 1; i < deltaCount; ++i) { - segments[i].delta = boundUint40(segments[i].delta, 1, maxDelta); + // Precompute the first segment duration. + segments[0].duration = uint40(_bound(segments[0].duration, 1, 100)); + + // Bound the durations so that none is zero and the calculations don't overflow. + uint256 durationCount = segments.length; + uint40 maxDuration = (MAX_UNIX_TIMESTAMP - segments[0].duration) / uint40(durationCount); + for (uint256 i = 1; i < durationCount; ++i) { + segments[i].duration = boundUint40(segments[i].duration, 1, maxDuration); } } } - /// @dev Fuzzes the segment milestones. - function fuzzSegmentMilestones(LockupDynamic.Segment[] memory segments, uint40 startTime) internal view { + /// @dev Fuzzes the segment timestamps. + function fuzzSegmentTimestamps(LockupDynamic.Segment[] memory segments, uint40 startTime) internal view { // Return here if there's only one segment to not run into division by zero. uint40 segmentCount = uint40(segments.length); if (segmentCount == 1) { // The end time must be in the future. uint40 currentTime = getBlockTimestamp(); - segments[0].milestone = (startTime < currentTime ? currentTime : startTime) + 2 days; + segments[0].timestamp = (startTime < currentTime ? currentTime : startTime) + 2 days; return; } - // The first milestones is precomputed to avoid an underflow in the first loop iteration. We have to - // add 1 because the first milestone must be greater than the start time. - segments[0].milestone = startTime + 1 seconds; + // The first timestamps is precomputed to avoid an underflow in the first loop iteration. We have to + // add 1 because the first timestamp must be greater than the start time. + segments[0].timestamp = startTime + 1 seconds; - // Fuzz the milestones while preserving their order in the array. For each milestone, set its initial guess - // as the sum of the starting milestone and the step size multiplied by the current index. This ensures that - // the initial guesses are evenly spaced. Next, we bound the milestone within a range of half the step size + // Fuzz the timestamps while preserving their order in the array. For each timestamp, set its initial guess + // as the sum of the starting timestamp and the step size multiplied by the current index. This ensures that + // the initial guesses are evenly spaced. Next, we bound the timestamp within a range of half the step size // around the initial guess. - uint256 start = segments[0].milestone; - uint40 step = (MAX_UNIX_TIMESTAMP - segments[0].milestone) / (segmentCount - 1); + uint256 start = segments[0].timestamp; + uint40 step = (MAX_UNIX_TIMESTAMP - segments[0].timestamp) / (segmentCount - 1); uint40 halfStep = step / 2; for (uint256 i = 1; i < segmentCount; ++i) { - uint256 milestone = start + i * step; - milestone = _bound(milestone, milestone - halfStep, milestone + halfStep); - segments[i].milestone = uint40(milestone); + uint256 timestamp = start + i * step; + timestamp = _bound(timestamp, timestamp - halfStep, timestamp + halfStep); + segments[i].timestamp = uint40(timestamp); } } } diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 86db15427..4e4997f55 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -31,24 +31,24 @@ abstract contract Utils is StdUtils, PRBMathUtils { return uint40(block.timestamp); } - /// @dev Turns the segments with deltas into canonical segments, which have milestones. - function getSegmentsWithMilestones(LockupDynamic.SegmentWithDelta[] memory segments) + /// @dev Turns the segments with durations into canonical segments, which have timestamps. + function getSegmentsWithTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) internal view - returns (LockupDynamic.Segment[] memory segmentsWithMilestones) + returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) { unchecked { - segmentsWithMilestones = new LockupDynamic.Segment[](segments.length); - segmentsWithMilestones[0] = LockupDynamic.Segment({ + segmentsWithTimestamps = new LockupDynamic.Segment[](segments.length); + segmentsWithTimestamps[0] = LockupDynamic.Segment({ amount: segments[0].amount, exponent: segments[0].exponent, - milestone: getBlockTimestamp() + segments[0].delta + timestamp: getBlockTimestamp() + segments[0].duration }); for (uint256 i = 1; i < segments.length; ++i) { - segmentsWithMilestones[i] = LockupDynamic.Segment({ + segmentsWithTimestamps[i] = LockupDynamic.Segment({ amount: segments[i].amount, exponent: segments[i].exponent, - milestone: segmentsWithMilestones[i - 1].milestone + segments[i].delta + timestamp: segmentsWithTimestamps[i - 1].timestamp + segments[i].duration }); } } From da153a80470dc6559fa6de82b80705ff93e407f1 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 24 Jan 2024 15:26:23 +0200 Subject: [PATCH 040/132] test: update Precompiles bytecode --- test/utils/Precompiles.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 11069a5c4..45141e818 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -27,9 +27,9 @@ contract Precompiles { bytes public constant BYTECODE_COMPTROLLER = hex"60803461009857601f6102d538819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361022190816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816375829def1461014c57508063b5b3ca2c146100ac578063dcf844a7146100765763f851a4401461004e57600080fd5b346100725781600319360112610072576001600160a01b0360209254169051908152f35b5080fd5b503461007257602036600319011261007257806020926001600160a01b0361009c6101f9565b1681526001845220549051908152f35b50346100725780600319360112610072576100c56101f9565b602435906001600160a01b0390818554163381036101245750907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526001602052808520928084549455815193845260208401523392a380f35b84516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b83903461007257602036600319011261007257600435906001600160a01b03908183168093036101f55783549182163381036101d25750507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6331b339a960e21b82526001600160a01b03166004820152336024820152604490fd5b8380fd5b600435906001600160a01b038216820361020f57565b600080fdfea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0346200046e57601f62005ee938819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615a559081620004948239608051816135fb015260a051818181610f57015261371c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126c15750806306fdde03146125fc578063081812fc146125de578063095ea7b31461244a5780631400ecec146123a557806316844456146120e15780631c1cdd4c1461207b5780631e99d5691461205d57806323b872dd1461203457806339a73c0314611ff157806340e58ee514611d9d578063425d30dd14611d7f57806342842e0e14611d2f57806342966c6814611b9f5780634857501f14611b295780634869e12d14611aed5780635fe3b56714611ac65780636352211e14611aa85780636d0cee7514611a5057806370a08231146119a657806375829def146119145780637cad6cd1146118425780637de6b1db146116325780638659c27014611339578063894e9a0d146110cc5780638bad38dd146110505780638f69b99314610fcd5780639067b67714610f7a5780639188ec8414610f3f57806395d89b4114610e2f578063a22cb46514610d5e578063a2ffb89714610c7c578063a6202bf214610b73578063a80fc07114610b1e578063ad35efd414610abb578063b256456914610a9d578063b637b86514610a3d578063b88d4fde146109b4578063b8a3be661461097d578063b971302a1461094e578063bc063e1a1461092b578063bc2be1be146108d8578063c156a11d14610820578063c33cd35e146106c1578063c87b56dd1461058e578063cc364f48146104f4578063d4dbd20b1461049f578063d511609f14610450578063d975dfed14610403578063e985e9c5146103ac578063ea5ead191461037e578063eac8f5b814610312578063f590c176146102ea578063f851a440146102c35763fdd46d601461027c57600080fd5b346102be5760603660031901126102be576102956127ee565b6044356001600160801b03811681036102be576102bc916102b46135f1565b600435613249565b005b600080fd5b346102be5760003660031901126102be5760206001600160a01b0360005416604051908152f35b346102be5760203660031901126102be576020610308600435612e24565b6040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102be5760403660031901126102be576102bc60043561039d6127ee565b6103a6826143c6565b91612e55565b346102be5760403660031901126102be576103c56127d8565b6103cd6127ee565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916143c6565b6001600160801b0360405191168152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602060026040600020015460801c604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102be5760203660031901126102be576004356000602060405161051881612928565b828152015280600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526040806000205464ffffffffff82519161055b83612928565b818160a01c16835260c81c16602082015261058c825180926020908164ffffffffff91828151168552015116910152565bf35b346102be576020806003193601126102be57600435906105cc6105c78360005260056020526001600160a01b0360406000205416151590565b612ba7565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106b55760009261063c575b506106386040519282849384528301906127b3565b0390f35b9091503d806000833e61064f8183612975565b81019082818303126102be5780519067ffffffffffffffff82116102be570181601f820112156102be57805161068481612997565b926106926040519485612975565b8184528482840101116102be576106ae91848085019101612790565b9082610623565b6040513d6000823e3d90fd5b346102be57600319602036820181136102be5760043567ffffffffffffffff928382116102be576101409082360301126102be576106fd6135f1565b6040519261070a8461290b565b61071682600401612804565b845261072460248301612a35565b6020850152610735604483016128e2565b6040850152610746606483016128e2565b91606092606086015261075b60848201612804565b608086015261076c60a482016129b3565b60a086015261077d60c48201612804565b60c086015261078f3660e48301612ad0565b60e08601526101248101359182116102be5701366023820112156102be576004810135926107bc84612a1d565b936107ca6040519586612975565b80855260246060602087019202840101923684116102be57602401905b838210610808576020610800888861010082015261366e565b604051908152f35b8285916108153685612a47565b8152019101906107e7565b346102be5760403660031901126102be5760043561083c6127ee565b906108456135f1565b80600052600b60205260ff60016040600020015460a81c1615610367578060005260056020526001600160a01b0360406000205416918233036108b5576102bc9261088f836143c6565b6001600160801b0381166108a4575b506140df565b6108af908285612e55565b8461089e565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102be5760003660031901126102be57602060405167016345785d8a00008152f35b346102be5760203660031901126102be57602061096c600435612ded565b6001600160a01b0360405191168152f35b346102be5760203660031901126102be57600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102be5760803660031901126102be576109cd6127d8565b6109d56127ee565b6064359167ffffffffffffffff83116102be57366023840112156102be57826004013591610a0283612997565b92610a106040519485612975565b80845236602482870101116102be5760208160009260246102bc9801838801378501015260443591612d57565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052610638610a896004604060002001612c90565b60405191829160208352602083019061287e565b346102be5760203660031901126102be576020610308600435612d20565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757610af590613f79565b6040516005821015610b08576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102be5760203660031901126102be57610b8c6127d8565b6001600160a01b038060005416338103610c5357508116908160005260026020526001600160801b0360406000205416908115610c225781610bf49184600052600260205260406000206fffffffffffffffffffffffffffffffff198154169055339061435e565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102be5760603660031901126102be5767ffffffffffffffff6004358181116102be57610cae90369060040161284d565b9190610cb86127ee565b916044359081116102be57610cd190369060040161284d565b92610cda6135f1565b838503610d275760005b858110610ced57005b80610d21610cfe6001938988612c17565b3584610d13610d0e858b8a612c17565b612abc565b91610d1c6135f1565b613249565b01610ce4565b60448585604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102be5760403660031901126102be57610d776127d8565b602435908115158092036102be576001600160a01b031690813314610deb57336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102be5760003660031901126102be5760405160006004549060018260011c9160018416918215610f35575b6020948585108414610f1f578587948686529182600014610eff575050600114610ea2575b50610e8e92500383612975565b6106386040519282849384528301906127b3565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610ee7575050610e8e935082010185610e81565b80548389018501528794508693909201918101610ed0565b60ff191685820152610e8e95151560051b8501019250879150610e819050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610e5c565b346102be5760003660031901126102be5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c161561036757600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761100790613f79565b600581101580610b085760028214908115611043575b8115611031575b6020826040519015158152f35b9050610b085760046020911482611024565b505060038114600061101d565b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c53575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102be5760203660031901126102be5760606101406040516110ee81612958565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152611132612c3d565b6101208201520152600435600052600b60205260ff60016040600020015460a81c161561132157600435600052600b602052604060002061121560046040519261117b84612958565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015261120960028201612c5c565b61012085015201612c90565b610140820152611226600435613f79565b906005821015610b085760026101409214611315575b610638604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130161012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c083019061287e565b6000606082015261123c565b602460405162b8e7e760e51b81526004356004820152fd5b346102be576020806003193601126102be5760043567ffffffffffffffff81116102be5761136b90369060040161284d565b906113746135f1565b6000915b80831061138157005b61138c838284612c17565b35926113966135f1565b61139f84612b70565b156113bc5760248460405190634a5541ef60e01b82526004820152fd5b6113c884929394612e24565b61161a576113ec82600052600b6020526001600160a01b0360406000205416331490565b156108b5576113fa82613586565b82600052600b8087526114136002604060002001612c5c565b906001600160801b0392838351168482161015611602578560005281895260ff60406000205460f01c16156115ea579061148182858b6114777f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509683895116612a04565b9601511690612a04565b9580600052818a526040600020938a855498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617875560038882169788156115d0575b0197831697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a16958691600584528b604060002054169687945260019b8c60406000200154169461151d8b858861435e565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b61157d575b5050505050019190611378565b813b156102be5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16115c1575b80808080611570565b6115ca90612944565b856115b8565b60018101600160a01b60ff60a01b198254161790556114c9565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102be576020806003193601126102be57600435906116506135f1565b81600052600b815260ff60016040600020015460a81c161561182b5761167582613f79565b6005811015610b08576004810361169e5760248360405190634a5541ef60e01b82526004820152fd5b600381036116be576024836040519063fe19f19f60e01b82526004820152fd5b600214611813576116e582600052600b6020526001600160a01b0360406000205416331490565b156108b55781600052600b815260ff60406000205460f01c16156117fb5781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b61178c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102be57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af115611760576117f590612944565b83611760565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102be5760203660031901126102be576004356001600160a01b03908181168091036102be578160005416338103610c535750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116118fe5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102be5760203660031901126102be5761192d6127d8565b6000546001600160a01b038082169233840361197f576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102be5760203660031901126102be576001600160a01b036119c76127d8565b1680156119e65760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57600435611a876105c78260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102be5760203660031901126102be57602061096c600435612bf2565b346102be5760003660031901126102be5760206001600160a01b0360015416604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675761043f6020916142e3565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576000611b6582613f79565b6005811015610b0857600203611b83575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611b76565b346102be5760203660031901126102be57600435611bbb6135f1565b611bc481612b70565b15611cfe57611bd28161427a565b15611cde57611be081612bf2565b611be982612d20565b159081611cd5575b81611cc2575b50611caa57602081611c297ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612bf2565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611bf7565b60009150611bf1565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102be57611d3d36612818565b60405191602083019383851067ffffffffffffffff861117611d69576102bc9460405260008452612d57565b634e487b7160e01b600052604160045260246000fd5b346102be5760203660031901126102be576020610308600435612b70565b346102be576020806003193601126102be5760043590611dbb6135f1565b611dc482612b70565b15611de15760248260405190634a5541ef60e01b82526004820152fd5b611dea82612e24565b61161a57611e0e82600052600b6020526001600160a01b0360406000205416331490565b156108b557611e1c82613586565b9180600052600b8252611e356002604060002001612c5c565b906001600160801b03938483511685821610156118135781600052600b845260ff60406000205460f01c16156117fb57808585611e78611e829483885116612a04565b9501511690612a04565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161787556003888616978815611fd7575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b87526001604060002001541694611f608d858861435e565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b611f9257005b813b156102be5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611fce57005b6102bc90612944565b60018101600160a01b60ff60a01b19825416179055611eeb565b346102be5760203660031901126102be576001600160a01b036120126127d8565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102be576102bc61204536612818565b916120586120538433614000565b612aff565b6140df565b346102be5760003660031901126102be576020600954604051908152f35b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c1615610367576120b590613f79565b6005811015610b085780602091159081156120d6575b506040519015158152f35b6001915014826120cb565b346102be57602060031981813601126102be576004359067ffffffffffffffff908183116102be57610120833603918201126102be5761211f6135f1565b61010483013590602219018112156102be578201916004830135928284116102be57602481016060916060860280360383136102be5760249061216188612a1d565b9761216f604051998a612975565b8852888801920101913683116102be57905b8783831061238e5787878782519061219882612a1d565b916121a66040519384612975565b808352601f196121b582612a1d565b018660005b8281106123785750505064ffffffffff90814216946001600160801b0396876121e28261364d565b515116828a6121f08461364d565b51015116858060406122018661364d565b510151168a01169060405192612216846128ef565b83528b830152604082015261222a8761364d565b526122348661364d565b506001938660015b8a8c8783106122f757908b846001600160a01b038c60a4810135828116908190036102be57610800956122b7956122e79461227960248601612a9b565b61228560448701612a9b565b61229160648801612aa8565b9161229e88600401612aa8565b94846122ac60848b01612abc565b966040519d8e61290b565b168c528d8c0152151560408b0152151560608a01521660808801521660a086015260c085015260c4369101612ad0565b60e083015261010082015261366e565b88938580604061232b8b8661231b8a8e9a612312828d61365a565b5151169a61365a565b510151169460001989019061365a565b5101511681604061233c888c61365a565b5101511601169160405193612350856128ef565b84528301526040820152612364828b61365a565b5261236f818a61365a565b5001879061223c565b612380612c3d565b8282880101520187906121ba565b849161239a3685612a47565b815201910190612181565b346102be5760203660031901126102be5760043580600052600b60205260ff60016040600020015460a81c16156103675760209060009080600052600b8352604060002060ff815460f01c1680612438575b61240f575b50506001600160801b0360405191168152f35b61243192506001600160801b03600261242b9201541691613586565b90612a04565b82806123fc565b5060ff600182015460a01c16156123f7565b346102be5760403660031901126102be576124636127d8565b602435906001600160a01b03808061247a85612bf2565b169216918083146125745780331490811561254f575b50156124e5578260005260076020526040600020826001600160a01b03198254161790556124bd83612bf2565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff6040600020541684612490565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102be5760203660031901126102be57602061096c6004356129c7565b346102be5760003660031901126102be5760405160006003549060018260011c91600184169182156126b7575b6020948585108414610f1f578587948686529182600014610eff57505060011461265a5750610e8e92500383612975565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b85831061269f575050610e8e935082010185610e81565b80548389018501528794508693909201918101612688565b92607f1692612629565b346102be5760203660031901126102be57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102be57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612766575b811561273c575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612735565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061272e565b60005b8381106127a35750506000910152565b8181015183820152602001612793565b906020916127cc81518092818552858086019101612790565b601f01601f1916010190565b600435906001600160a01b03821682036102be57565b602435906001600160a01b03821682036102be57565b35906001600160a01b03821682036102be57565b60609060031901126102be576001600160a01b039060043582811681036102be579160243590811681036102be579060443590565b9181601f840112156102be5782359167ffffffffffffffff83116102be576020808501948460051b0101116102be57565b90815180825260208080930193019160005b82811061289e575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612890565b359081151582036102be57565b6060810190811067ffffffffffffffff821117611d6957604052565b610120810190811067ffffffffffffffff821117611d6957604052565b6040810190811067ffffffffffffffff821117611d6957604052565b67ffffffffffffffff8111611d6957604052565b610160810190811067ffffffffffffffff821117611d6957604052565b90601f8019910116810190811067ffffffffffffffff821117611d6957604052565b67ffffffffffffffff8111611d6957601f01601f191660200190565b35906001600160801b03821682036102be57565b6129ea6105c78260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116118fe57565b67ffffffffffffffff8111611d695760051b60200190565b359064ffffffffff821682036102be57565b91908260609103126102be57604051612a5f816128ef565b8092612a6a816129b3565b825260208101359067ffffffffffffffff821682036102be576040612a96918193602086015201612a35565b910152565b3580151581036102be5790565b356001600160a01b03811681036102be5790565b356001600160801b03811681036102be5790565b91908260409103126102be57604051612ae881612928565b6020808294612af681612804565b84520135910152565b15612b0657565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460a01c1690565b15612bae57565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c14811515612ba7565b90565b9190811015612c275760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190612c4a826128ef565b60006040838281528260208201520152565b90604051612c69816128ef565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612c9c81612a1d565b92604093612cad6040519182612975565b82815280946020809201926000526020600020906000935b858510612cd457505050505050565b60018481928451612ce4816128ef565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cc5565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260ff60016040600020015460b01c1690565b90612d7b939291612d6b6120538433614000565b612d768383836140df565b6149fa565b15612d8257565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561036757600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460a81c161561036757600052600b60205260406000205460f81c90565b92919092612e616135f1565b600093612e6d82612b70565b61323157612e9182600052600b6020526001600160a01b0360406000205416331490565b90811593848095613221575b61320257838752602094600586526001600160a01b039060409482868b20541690806131f6575b6131d15782851680156131a8576001600160801b039081861691821561317857612f0a8a60028f8c908f600b90612efa866142e3565b9583525220015460801c90612a04565b8181168411613147575090897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c8f60018d8b928d9b9a9998612f9b612f69612f528a612ded565b9e8a8552600b89526002868620015460801c6143ee565b898452600b885260028585200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c5c565b90612fb6818884015116928286818351169201511690612a04565b161115613119575b868152600b85522001541694612fd5818d8861435e565b8c51908152a4803314158061310f575b6130a9575b508061309f575b613025575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b88929116803b1561309b578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613083575b808080612ff6565b61308d8691612944565b613097578461307b565b8480fd5b8280fd5b50803b1515612ff1565b8a813b1561310c578751636fd110e960e01b8152600481018a90523360248201526001600160a01b03881660448201526001600160801b0387166064820152918290608490829084905af115612fea57613105909a919a612944565b9838612fea565b80fd5b50803b1515612fe5565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612fbe565b895163287ecaef60e21b8152600481018c90526001600160801b038981166024830152919091166044820152606490fd5b60248a8a51907fd2aabcd90000000000000000000000000000000000000000000000000000000082526004820152fd5b600487517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b6064878487895192632dcbf6b960e11b84526004840152336024840152166044820152fd5b50808386161415612ec4565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b5061322b8461427a565b15612e9d565b60248260405190634a5541ef60e01b82526004820152fd5b9291909261325681612b70565b61356e5761327a81600052600b6020526001600160a01b0360406000205416331490565b801592838061355e575b61353f57600095838752602094600586526001600160a01b039060409482868b2054169080613533575b61350e5782841680156131a8576001600160801b0390818716918215613178576132d78a6143c6565b81811684116134dd575090897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c8f60018d8b928e9b9a999861331f612f69612f528a612ded565b9061333a818884015116928286818351169201511690612a04565b1611156134af575b868152600b85522001541694613359818c8861435e565b8c51908152a480331415806134a5575b613446575b508061343c575b6133a857505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b1690813b15613438578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613429575b85948180612ff6565b61343290612944565b38613420565b8780fd5b50803b1515613375565b8a813b1561310c578751636fd110e960e01b8152600481018a90523360248201526001600160a01b03871660448201526001600160801b0388166064820152918290608490829084905af11561336e5761349f90612944565b3861336e565b50803b1515613369565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613342565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b6064878486895192632dcbf6b960e11b84526004840152336024840152166044820152fd5b508083851614156132ae565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b506135688361427a565b15613284565b60249060405190634a5541ef60e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c1610156135e75760c81c1611156135d55760040154600110156135cc57612c14906144dd565b612c1490614409565b6001600160801b039150600201541690565b5050505050600090565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361362357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c275760200190565b8051821015612c275760209160051b010190565b906001600160a01b036001541660206001600160a01b0360c0850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106b557600090613f45575b6136ef91506001600160801b0360a08501511690602060e08601510151916146c8565b6001600160801b0381511661010084015164ffffffffff6020860151168215613f1b5781518015613ef1577f00000000000000000000000000000000000000000000000000000000000000008111613ec0575064ffffffffff60406137538461364d565b51015116811015613e695750600090819082815184905b808210613dd6575050505064ffffffffff421664ffffffffff8216811015613d965750506001600160801b0316808203613d5f5750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b0360c083015116600184015490750100000000000000000000000000000000000000000060408501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff000000000000000000000000000000000000000000006060890151151560b01b16921617171760018601556001600160a01b038451169161010085015192604061388585519560001987019061365a565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060208b015160a01b169660c81b169460f01b16911617171717845560005b818110613c8f575050600185016009556001600160a01b0360c08301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b0360c0840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036080830151168015613c4b576139cc6139c68760005260056020526001600160a01b0360406000205416151590565b15614807565b6139d586612d20565b1580613c42575b80613c3a575b613c225760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613a2d6139c68960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a1613abd6001600160a01b0360c0840151166001600160801b03808451168160208601511601169030903390614852565b6001600160801b0360408201511680613bf3575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb613bb06001600160a01b03845116926001600160a01b03608086015116946001600160a01b0360c08201511696613be8613bc860408401511515928c606086015115156001600160a01b0360e061010089015194549864ffffffffff6040519a613b5c8c612928565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e088015286019061287e565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613c1c906001600160a01b0360c0850151166001600160a01b0360e08601515116903390614852565b38613ad1565b60248660405190630da9b01360e01b82526004820152fd5b5060006139e2565b508015156139dc565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b613c9e8161010086015161365a565b519060048601549168010000000000000000831015611d695760018301806004890155831015612c275760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613921565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613dfa906001600160801b03613df1858861365a565b515116906143ee565b9364ffffffffff806040613e0e868561365a565b51015116941680851115613e2c57506001849301919291909261376a565b8385606492604051927f7b0bada8000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613e7a8461364d565b5101516040517fb4c9e52c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d602011613f71575b81613f5f60209383612975565b810103126102be576136ef90516136cc565b3d9150613f52565b80600052600b602052604060002060ff600182015460a01c16600014613fa0575050600490565b805460f81c613ff9575460a01c64ffffffffff164210613ff357613fc381613586565b90600052600b6020526001600160801b038060026040600020015416911610600014613fee57600190565b600290565b50600090565b5050600390565b906001600160a01b03808061401484612bf2565b16931691838314938415614047575b508315614031575b50505090565b61403d919293506129c7565b161438808061402b565b909350600052600860205260406000208260005260205260ff604060002054169238614023565b1561407557565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b9061410892916140ee83612bf2565b916001600160a01b0394859384809416968791161461406e565b16908115806142115761411a84612d20565b159081614208575b50806141ff575b6141e757918084926141697ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661416285612bf2565b161461406e565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515614129565b90501538614122565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b60009080825260056020526001600160a01b0380604084205416928333149384156142bf575b505082156142ad57505090565b9091506142ba33926129c7565b161490565b60ff92945090604091815260086020528181203382526020522054169138806142a0565b80600052600b6020526142fc6002604060002001612c5c565b81600052600b602052604060002060ff600182015460a01c1660001461432f57506001600160801b039150602001511690565b5460f81c6143415750612c1490613586565b612c1491506001600160801b036040818351169201511690612a04565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611d69576143c4926040526148bd565b565b612c14906143d3816142e3565b90600052600b60205260026040600020015460801c90612a04565b9190916001600160801b03808094169116019182116118fe57565b64ffffffffff61443e600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614b8d565b91808252600b602052600460408320018054156144c95790829167ffffffffffffffff935261449b6020832054828452600b6020526144966001600160801b03968760026040882001541696879360801c1690614c7d565b614ceb565b9283136144b15750506144ad90614dd5565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b60205260409081812082519361450485612958565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c16151561010088015261014061459f600461459060028801612c5c565b966101208b0197885201612c90565b97019187835280876145b1889a61364d565b5101511693828288965b16106146905750916146456144969284888161464a98976001600160801b039e8f6145e78b8a5161365a565b5151169d8a8f9b602061460467ffffffffffffffff928d5161365a565b5101511699848361461684845161365a565b5101511696508115614684576146349293505190600019019061365a565b5101511680925b0316920316614b8d565b614c7d565b92831361466357505061465d8391614dd5565b16011690565b51602001519293928316928416831015915061467f9050575090565b905090565b5050505116809261463b565b8094986001600160801b0390816146a88c885161365a565b51511601169801938282808a6146bf89895161365a565b510151166145bb565b9092916146d3612c3d565b936001600160801b03928381169182156147df5767016345785d8a00008082116147a857808511614771575061471d8561470e819386615901565b16946020890195865284615901565b1691846147346040890194808652828751166143ee565b16101561475b5761474d84918261475695511690612a04565b91511690612a04565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516147f2816128ef565b60008152600060208201526000604082015290565b1561480e57565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611d69576143c4926040525b6001600160a01b03169061491d6040516148d681612928565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16149176149ca565b916159b0565b8051918215918483156149a2575b5050509050156149385750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b9193818094500103126149c65782015190811515820361310c57508038808461492b565b5080fd5b3d156149f5573d906149db82612997565b916149e96040519384612975565b82523d6000602084013e565b606090565b9290803b15614b8457614a64916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906127b3565b03916000968791165af190829082614b23575b5050614afd57614a856149ca565b80519081614af85760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614b7c575b81614b4060209383612975565b810103126149c65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361310c5750903880614a77565b3d9150614b33565b50505050600190565b600160ff1b808214908115614c73575b50614c49576000811215614c4057614bc6816000035b6000841215614c39578360000390614e11565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614c025760001991181315614bfc5790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614e11565b614bc681614bb3565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614b9d565b80614c985750614c9357670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614ce5575080614cbd575050670de0b6b3a764000090565b670de0b6b3a76400008114614ce157614cdc90614496612c1493614f0b565b61504d565b5090565b91505090565b600160ff1b808214908115614dcb575b50614da1576000811215614d9857614d24816000035b6000841215614d91578360000390615901565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614d5a5760001991181315614bfc5790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615901565b614d2481614d11565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614cfb565b60008112614de05790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ecd5782851015614e9157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614edb570490565b634e487b7160e01b600052601260045260246000fd5b8015614edb576ec097ce7bc90715b34b9f10000000000590565b8060008083131561501c57670de0b6b3a764000092838112614ff957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614fed57506706f05b59d3b20000905b848213614fc15750505050500290565b808391020590671bc16d674ec80000821215614fe0575b831d90614fb1565b8091950194831d90614fd8565b93505093925050020290565b6000199392508015614edb576ec097ce7bc90715b34b9f10000000000591614f2c565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b600081121561507c5768033dd1780914b97114198112613ff3576150739060000361504d565b612c1490614ef1565b680a688906bd8affffff81136158d057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166157b3575b66ff00000000000083166156ab575b65ff000000000083166155ab575b64ff0000000083166154b3575b63ff00000083166153c3575b62ff000083166152db575b61ff0083166151fb575b60ff8316615124575b02911c60bf031c90565b608083166151e9575b8383166151d7575b602083166151c5575b601083166151b3575b600883166151a1575b6004831661518f575b6002831661517d575b600183161561511a576801000000000000000102831c61511a565b6801000000000000000102831c615162565b6801000000000000000302831c615159565b6801000000000000000602831c615150565b6801000000000000000b02831c615147565b6801000000000000001602831c61513e565b6801000000000000002c02831c615135565b6801000000000000005902831c61512d565b61800083166152c9575b61400083166152b7575b61200083166152a5575b6110008316615293575b6108008316615281575b610400831661526f575b610200831661525d575b61010083161561511157680100000000000000b102831c615111565b6801000000000000016302831c615241565b680100000000000002c602831c615237565b6801000000000000058c02831c61522d565b68010000000000000b1702831c615223565b6801000000000000162e02831c615219565b68010000000000002c5d02831c61520f565b680100000000000058b902831c615205565b6280000083166153b1575b62400000831661539f575b62200000831661538d575b62100000831661537b575b620800008316615369575b620400008316615357575b620200008316615345575b62010000831615615107576801000000000000b17202831c615107565b680100000000000162e402831c615328565b6801000000000002c5c802831c61531d565b68010000000000058b9102831c615312565b680100000000000b172102831c615307565b68010000000000162e4302831c6152fc565b680100000000002c5c8602831c6152f1565b6801000000000058b90c02831c6152e6565b638000000083166154a1575b6340000000831661548f575b6320000000831661547d575b6310000000831661546b575b63080000008316615459575b63040000008316615447575b63020000008316615435575b63010000008316156150fc5768010000000000b1721802831c6150fc565b6801000000000162e43002831c615417565b68010000000002c5c86002831c61540b565b680100000000058b90c002831c6153ff565b6801000000000b17217f02831c6153f3565b680100000000162e42ff02831c6153e7565b6801000000002c5c85fe02831c6153db565b68010000000058b90bfc02831c6153cf565b6480000000008316615599575b6440000000008316615587575b6420000000008316615575575b6410000000008316615563575b6408000000008316615551575b640400000000831661553f575b640200000000831661552d575b6401000000008316156150f057680100000000b17217f802831c6150f0565b68010000000162e42ff102831c61550e565b680100000002c5c85fe302831c615501565b6801000000058b90bfce02831c6154f4565b68010000000b17217fbb02831c6154e7565b6801000000162e42fff002831c6154da565b68010000002c5c8601cc02831c6154cd565b680100000058b90c0b4902831c6154c0565b658000000000008316615699575b654000000000008316615687575b652000000000008316615675575b651000000000008316615663575b650800000000008316615651575b65040000000000831661563f575b65020000000000831661562d575b650100000000008316156150e3576801000000b17218355102831c6150e3565b680100000162e430e5a202831c61560d565b6801000002c5c863b73f02831c6155ff565b68010000058b90cf1e6e02831c6155f1565b680100000b1721bcfc9a02831c6155e3565b68010000162e43f4f83102831c6155d5565b680100002c5c89d5ec6d02831c6155c7565b6801000058b91b5bc9ae02831c6155b9565b668000000000000083166157a1575b6640000000000000831661578f575b6620000000000000831661577d575b6610000000000000831661576b575b66080000000000008316615759575b66040000000000008316615747575b66020000000000008316615735575b66010000000000008316156150d55768010000b17255775c0402831c6150d5565b6801000162e525ee054702831c615714565b68010002c5cc37da949202831c615705565b680100058ba01fb9f96d02831c6156f6565b6801000b175effdc76ba02831c6156e7565b680100162f3904051fa102831c6156d8565b6801002c605e2e8cec5002831c6156c9565b68010058c86da1c09ea202831c6156ba565b67800000000000000083166158b1575b674000000000000000831661589f575b672000000000000000831661588d575b671000000000000000831661587b575b6708000000000000008316615869575b6704000000000000008316615857575b6702000000000000008316615845575b6701000000000000008316156150c657680100b1afa5abcbed6102831c6150c6565b68010163da9fb33356d802831c615823565b680102c9a3e778060ee702831c615813565b6801059b0d31585743ae02831c615803565b68010b5586cf9890f62a02831c6157f3565b6801172b83c7d517adce02831c6157e3565b6801306fe0a31b7152df02831c6157d3565b5077b504f333f9de6484800000000000000000000000000000006157c3565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461599f57670de0b6b3a7640000908183101561596857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b91929015615a1157508151156159c4575090565b3b156159cd5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015615a245750805190602001fd5b6108d49060405191829162461bcd60e51b83526020600484015260248301906127b356fea164736f6c6343000817000a"; + hex"60c0346200046e57601f62005e5d38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a05260016009556040516159c9908162000494823960805181613873015260a051818181610d2101526139940152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126815750806306fdde03146125bc578063081812fc1461259e578063095ea7b31461240a5780631400ecec146123655780631c1cdd4c146122ff5780631e99d569146122e157806323b872dd146122b857806331df3d48146121b557806339a73c031461217257806340e58ee514611f1e578063425d30dd14611f0057806342842e0e14611eb057806342966c6814611d205780634426757014611cf95780634857501f14611c835780634869e12d14611c475780634cc55e1114611b4c57806354c02292146118c75780635fe3b567146118a05780636352211e146118825780636d0cee751461182a57806370a082311461178057806375829def146116ee5780637cad6cd11461161c5780637de6b1db1461140c5780638659c27014611103578063894e9a0d14610e965780638bad38dd14610e1a5780638f69b99314610d975780639067b67714610d445780639188ec8414610d0957806395d89b4114610bf9578063a22cb46514610b28578063a6202bf214610a1f578063a80fc071146109ca578063ad35efd414610967578063b256456914610949578063b637b865146108e9578063b88d4fde14610860578063b8a3be6614610829578063b971302a146107fa578063bc063e1a146107d7578063bc2be1be14610784578063c156a11d146106cc578063c87b56dd14610599578063cc364f48146104ff578063d4dbd20b146104aa578063d511609f1461045b578063d975dfed1461040e578063e985e9c5146103b7578063ea5ead1914610389578063eac8f5b81461031d578063f590c176146102f5578063f851a440146102ce5763fdd46d601461028757600080fd5b346102c95760603660031901126102c9576102a06127ae565b6044356001600160801b03811681036102c9576102c7916102bf613869565b600435613203565b005b600080fd5b346102c95760003660031901126102c95760206001600160a01b0360005416604051908152f35b346102c95760203660031901126102c9576020610313600435612e30565b6040519015158152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102c95760403660031901126102c9576102c76004356103a86127ae565b6103b18261433a565b91612e61565b346102c95760403660031901126102c9576103d0612798565b6103d86127ae565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761044a60209161433a565b6001600160801b0360405191168152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602060026040600020015460801c604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102c95760203660031901126102c95760043560006020604051610523816128e8565b828152015280600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526040806000205464ffffffffff825191610566836128e8565b818160a01c16835260c81c166020820152610597825180926020908164ffffffffff91828151168552015116910152565bf35b346102c9576020806003193601126102c957600435906105d76105d28360005260056020526001600160a01b0360406000205416151590565b612bd9565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106c057600092610647575b50610643604051928284938452830190612773565b0390f35b9091503d806000833e61065a8183612935565b81019082818303126102c95780519067ffffffffffffffff82116102c9570181601f820112156102c957805161068f81612957565b9261069d6040519485612935565b8184528482840101116102c9576106b991848085019101612750565b908261062e565b6040513d6000823e3d90fd5b346102c95760403660031901126102c9576004356106e86127ae565b906106f1613869565b80600052600b60205260ff60016040600020015460a81c1615610372578060005260056020526001600160a01b036040600020541691823303610761576102c79261073b8361433a565b6001600160801b038116610750575b506136ce565b61075b908285612e61565b8461074a565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102c95760003660031901126102c957602060405167016345785d8a00008152f35b346102c95760203660031901126102c9576020610818600435612df9565b6001600160a01b0360405191168152f35b346102c95760203660031901126102c957600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102c95760803660031901126102c957610879612798565b6108816127ae565b6064359167ffffffffffffffff83116102c957366023840112156102c9578260040135916108ae83612957565b926108bc6040519485612935565b80845236602482870101116102c95760208160009260246102c79801838801378501015260443591612d63565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526106436109356004604060002001612c9c565b60405191829160208352602083019061283e565b346102c95760203660031901126102c9576020610313600435612d2c565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c1615610372576109a190613568565b60405160058210156109b4576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102c95760203660031901126102c957610a38612798565b6001600160a01b038060005416338103610aff57508116908160005260026020526001600160801b0360406000205416908115610ace5781610aa09184600052600260205260406000206fffffffffffffffffffffffffffffffff19815416905533906142d2565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102c95760403660031901126102c957610b41612798565b602435908115158092036102c9576001600160a01b031690813314610bb557336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102c95760003660031901126102c95760405160006004549060018260011c9160018416918215610cff575b6020948585108414610ce9578587948686529182600014610cc9575050600114610c6c575b50610c5892500383612935565b610643604051928284938452830190612773565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610cb1575050610c58935082010185610c4b565b80548389018501528794508693909201918101610c9a565b60ff191685820152610c5895151560051b8501019250879150610c4b9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610c26565b346102c95760003660031901126102c95760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257610dd190613568565b6005811015806109b45760028214908115610e0d575b8115610dfb575b6020826040519015158152f35b90506109b45760046020911482610dee565b5050600381146000610de7565b346102c95760203660031901126102c9576004356001600160a01b03908181168091036102c9578160005416338103610aff575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102c95760203660031901126102c9576060610140604051610eb881612918565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152610efc612c49565b6101208201520152600435600052600b60205260ff60016040600020015460a81c16156110eb57600435600052600b6020526040600020610fdf600460405192610f4584612918565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c161515610100850152610fd360028201612c68565b61012085015201612c9c565b610140820152610ff0600435613568565b9060058210156109b457600261014092146110df575b610643604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e0810151151561010085015261010081015115156101208501526110cb61012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c083019061283e565b60006060820152611006565b602460405162b8e7e760e51b81526004356004820152fd5b346102c9576020806003193601126102c95760043567ffffffffffffffff81116102c95761113590369060040161280d565b9061113e613869565b6000915b80831061114b57005b611156838284612b7e565b3592611160613869565b61116984612b47565b156111865760248460405190634a5541ef60e01b82526004820152fd5b61119284929394612e30565b6113f4576111b682600052600b6020526001600160a01b0360406000205416331490565b15610761576111c4826134fd565b82600052600b8087526111dd6002604060002001612c68565b906001600160801b03928383511684821610156113dc578560005281895260ff60406000205460f01c16156113c4579061122d82858b61122361131296838951166129c4565b96015116906129c4565b86600052818a52896040600020947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841617885560038986169889156113aa575b0198811698896fffffffffffffffffffffffffffffffff198254161790558a6001600160a01b038094169788946005875280604060002054169889975260016040600020015416966112e88c878a6142d2565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b611355575b5050505060019150019190611142565b803b156102c95760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161139b575b808080611345565b6113a490612904565b85611393565b60018101600160a01b60ff60a01b19825416179055611295565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102c9576020806003193601126102c9576004359061142a613869565b81600052600b815260ff60016040600020015460a81c16156116055761144f82613568565b60058110156109b457600481036114785760248360405190634a5541ef60e01b82526004820152fd5b60038103611498576024836040519063fe19f19f60e01b82526004820152fd5b6002146115ed576114bf82600052600b6020526001600160a01b0360406000205416331490565b156107615781600052600b815260ff60406000205460f01c16156115d55781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b611566575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102c957600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af11561153a576115cf90612904565b8361153a565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102c95760203660031901126102c9576004356001600160a01b03908181168091036102c9578160005416338103610aff5750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116116d85760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102c95760203660031901126102c957611707612798565b6000546001600160a01b0380821692338403611759576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102c95760203660031901126102c9576001600160a01b036117a1612798565b1680156117c05760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102c95760203660031901126102c9576004356118616105d28260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102c95760203660031901126102c9576020610818600435612c24565b346102c95760003660031901126102c95760206001600160a01b0360015416604051908152f35b346102c957602060031981813601126102c95760043567ffffffffffffffff918282116102c957610120823603918201126102c957611904613869565b60c482013590602219018112156102c95781016004810135908382116102c95760240160608202360381136102c95761193e913691612a78565b9182519161194b83612a60565b926119596040519485612935565b808452601f1961196882612a60565b018660005b828110611b365750505064ffffffffff90814216936001600160801b039687611995826138c5565b515116828a6119a3846138c5565b51015116858060406119b4866138c5565b5101511689011690604051926119c9846128cc565b83528b83015260408201526119dd886138c5565b526119e7876138c5565b506001938760015b8a8c878310611ab55790838b8b611a0881600401612bb8565b92611a1560248301612bb8565b92611a2260448401612ba4565b946064840135946001600160a01b03958681168091036102c957611aad98611a6d98611aa298611a5460848a01612bcc565b9481611a6260a48c01612bcc565b976040519d8e6128af565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612b18565b6101008201526138e6565b604051908152f35b889385806040611ae98b86611ad98a8e9a611ad0828d6138d2565b5151169a6138d2565b51015116946000198901906138d2565b51015116816040611afa888c6138d2565b5101511601169160405193611b0e856128cc565b84528301526040820152611b22828c6138d2565b52611b2d818b6138d2565b500188906119ef565b611b3e612c49565b82828901015201879061196d565b346102c95760403660031901126102c95767ffffffffffffffff6004358181116102c957611b7e90369060040161280d565b916024359081116102c957611b9790369060040161280d565b9091611ba1613869565b818403611c105760005b848110611bb457005b80611c0a611bc56001938886612b7e565b35611bd1838987612b7e565b3560005260056020526001600160a01b0360406000205416611bfc611bf785898b612b7e565b612ba4565b91611c05613869565b613203565b01611bab565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761044a602091614257565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c1615610372576000611cbf82613568565b60058110156109b457600203611cdd575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611cd0565b346102c95760003660031901126102c95760206001600160a01b03600a5416604051908152f35b346102c95760203660031901126102c957600435611d3c613869565b611d4581612b47565b15611e7f57611d53816141ee565b15611e5f57611d6181612c24565b611d6a82612d2c565b159081611e56575b81611e43575b50611e2b57602081611daa7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612c24565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611d78565b60009150611d72565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102c957611ebe366127d8565b60405191602083019383851067ffffffffffffffff861117611eea576102c79460405260008452612d63565b634e487b7160e01b600052604160045260246000fd5b346102c95760203660031901126102c9576020610313600435612b47565b346102c9576020806003193601126102c95760043590611f3c613869565b611f4582612b47565b15611f625760248260405190634a5541ef60e01b82526004820152fd5b611f6b82612e30565b6113f457611f8f82600052600b6020526001600160a01b0360406000205416331490565b1561076157611f9d826134fd565b9180600052600b8252611fb66002604060002001612c68565b906001600160801b03938483511685821610156115ed5781600052600b845260ff60406000205460f01c16156115d557808585611ff961200394838851166129c4565b95015116906129c4565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161787556003888616978815612158575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b875260016040600020015416946120e18d85886142d2565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b61211357005b813b156102c95760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161214f57005b6102c790612904565b60018101600160a01b60ff60a01b1982541617905561206c565b346102c95760203660031901126102c9576001600160a01b03612193612798565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102c9576003196020368201126102c95760043567ffffffffffffffff918282116102c9576101409082360301126102c9576121f0613869565b604051916121fd836128af565b612209826004016127c4565b8352612217602483016127c4565b602084015261222860448301612973565b6040840152612239606483016127c4565b606084015261224a608483016128a2565b608084015261225b60a483016128a2565b60a084015261226c60c48301612a4e565b60c084015260e48201359081116102c957810191366023840112156102c957611aa2611aad926122a86020953690602460048201359101612a78565b60e0840152610104369101612b18565b346102c9576102c76122c9366127d8565b916122dc6122d784336135ef565b6129dd565b6136ce565b346102c95760003660031901126102c9576020600954604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761233990613568565b60058110156109b457806020911590811561235a575b506040519015158152f35b60019150148261234f565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725760209060009080600052600b8352604060002060ff815460f01c16806123f8575b6123cf575b50506001600160801b0360405191168152f35b6123f192506001600160801b0360026123eb92015416916134fd565b906129c4565b82806123bc565b5060ff600182015460a01c16156123b7565b346102c95760403660031901126102c957612423612798565b602435906001600160a01b03808061243a85612c24565b169216918083146125345780331490811561250f575b50156124a5578260005260076020526040600020826001600160a01b031982541617905561247d83612c24565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff6040600020541684612450565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102c95760203660031901126102c9576020610818600435612987565b346102c95760003660031901126102c95760405160006003549060018260011c9160018416918215612677575b6020948585108414610ce9578587948686529182600014610cc957505060011461261a5750610c5892500383612935565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b85831061265f575050610c58935082010185610c4b565b80548389018501528794508693909201918101612648565b92607f16926125e9565b346102c95760203660031901126102c957600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102c957817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612726575b81156126fc575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836126f5565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126ee565b60005b8381106127635750506000910152565b8181015183820152602001612753565b9060209161278c81518092818552858086019101612750565b601f01601f1916010190565b600435906001600160a01b03821682036102c957565b602435906001600160a01b03821682036102c957565b35906001600160a01b03821682036102c957565b60609060031901126102c9576001600160a01b039060043582811681036102c9579160243590811681036102c9579060443590565b9181601f840112156102c95782359167ffffffffffffffff83116102c9576020808501948460051b0101116102c957565b90815180825260208080930193019160005b82811061285e575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612850565b359081151582036102c957565b610120810190811067ffffffffffffffff821117611eea57604052565b6060810190811067ffffffffffffffff821117611eea57604052565b6040810190811067ffffffffffffffff821117611eea57604052565b67ffffffffffffffff8111611eea57604052565b610160810190811067ffffffffffffffff821117611eea57604052565b90601f8019910116810190811067ffffffffffffffff821117611eea57604052565b67ffffffffffffffff8111611eea57601f01601f191660200190565b35906001600160801b03821682036102c957565b6129aa6105d28260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116116d857565b156129e457565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b359064ffffffffff821682036102c957565b67ffffffffffffffff8111611eea5760051b60200190565b929192612a8482612a60565b604094612a946040519283612935565b819584835260208093019160608096028501948186116102c957925b858410612ac05750505050505050565b86848303126102c957825190612ad5826128cc565b612ade85612973565b8252858501359067ffffffffffffffff821682036102c957828792838b950152612b09868801612a4e565b86820152815201930192612ab0565b91908260409103126102c957604051612b30816128e8565b6020808294612b3e816127c4565b84520135910152565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260ff60016040600020015460a01c1690565b9190811015612b8e5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102c95790565b356001600160a01b03811681036102c95790565b3580151581036102c95790565b15612be057565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c46811515612bd9565b90565b60405190612c56826128cc565b60006040838281528260208201520152565b90604051612c75816128cc565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612ca881612a60565b92604093612cb96040519182612935565b82815280946020809201926000526020600020906000935b858510612ce057505050505050565b60018481928451612cf0816128cc565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cd1565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260ff60016040600020015460b01c1690565b90612d87939291612d776122d784336135ef565b612d828383836136ce565b61496e565b15612d8e57565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260406000205460f81c90565b929192612e6c613869565b600093612e7882612b47565b6131eb576001600160a01b03928381169182156131c1576001600160801b03948582169586156131a9578589526020966005885260409583878c205416928382141580613199575b61315d57612ee88960028a8f600b8f612ed886614257565b9583525220015460801c906129c4565b818116841161312c575090887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b878f8c6001918c9b9a9998612f79612f47612f308a612df9565b9e8a8552600b89526002868620015460801c614362565b898452600b885260028585200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c68565b90612f948188840151169282868183511692015116906129c4565b1611156130fe575b868152600b85522001541694612fb3818c886142d2565b8b51908152a480331415806130f4575b61308e575b50811690813314159081613083575b5061300b575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b1561307f578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613067575b8080612fdd565b6130718691612904565b61307b5784613060565b8480fd5b8280fd5b90503b151538612fd7565b89813b156130f1578651636fd110e960e01b8152600481018990523360248201526001600160a01b03871660448201526001600160801b0386166064820152918290608490829084905af115612fc8576130ea90999199612904565b9738612fc8565b80fd5b50803b1515612fc3565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612f9c565b885163287ecaef60e21b8152600481018b90526001600160801b038881166024830152919091166044820152606490fd5b606489838a51917fb34359d300000000000000000000000000000000000000000000000000000000835260048301523360248301526044820152fd5b506131a3896141ee565b15612ec0565b6024866040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248260405190634a5541ef60e01b82526004820152fd5b9291909261321081612b47565b6134e5576001600160a01b03918285169081156131c1576001600160801b03958682169485156134cd576000978589526020966005885260409583878c2054169283821415806134bd575b61315d576132688961433a565b818116841161348c575090887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b878f8c6001918d9c9b9a99986132c8612f476132b18a612df9565b9f8a8552600b89526002868620015460801c614362565b906132e38188840151169282868183511692015116906129c4565b16111561345e575b868152600b85522001541694613302818a886142d2565b8b51908152a48033141580613454575b6133f5575b508216918233141590816133ea575b50613359575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156133e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16133d7575b859481612fdd565b6133e090612904565b386133cf565b8780fd5b90503b151538613326565b89813b156130f1578651636fd110e960e01b8152600481018990523360248201526001600160a01b03851660448201526001600160801b0387166064820152918290608490829084905af1156133175761344e90612904565b38613317565b50803b1515613312565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556132eb565b885163287ecaef60e21b8152600481018b90526001600160801b038981166024830152919091166044820152606490fd5b506134c7896141ee565b1561325b565b6024856040519063d2aabcd960e01b82526004820152fd5b60249060405190634a5541ef60e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c16101561355e5760c81c16111561354c57600401546001101561354357612c4690614451565b612c469061437d565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c1660001461358f575050600490565b805460f81c6135e8575460a01c64ffffffffff1642106135e2576135b2816134fd565b90600052600b6020526001600160801b0380600260406000200154169116106000146135dd57600190565b600290565b50600090565b5050600390565b906001600160a01b03808061360384612c24565b16931691838314938415613636575b508315613620575b50505090565b61362c91929350612987565b161438808061361a565b909350600052600860205260406000208260005260205260ff604060002054169238613612565b1561366457565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b906136f792916136dd83612c24565b916001600160a01b0394859384809416968791161461365d565b16908115806138005761370984612d2c565b1590816137f7575b50806137ee575b6137d657918084926137587ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661375185612c24565b161461365d565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515613718565b90501538613711565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361389b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612b8e5760200190565b8051821015612b8e5760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106c0576000906141ba575b61396891506001600160801b0360408501511690602061010086015101519161463c565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141905781518015614166577f00000000000000000000000000000000000000000000000000000000000000008111614135575064ffffffffff60406139cb846138c5565b510151168110156140de5750600090819082815184905b80821061404d575050505064ffffffffff421664ffffffffff821681101561400d5750506001600160801b0316808203613fd65750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606083015116600184015490750100000000000000000000000000000000000000000060808501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b038451169160e0850151926040613afc8551956000198701906138d2565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060c08b015160a01b169660c81b169460f01b16911617171717845560005b818110613f07575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036020830151168015613ec357613c43613c3d8760005260056020526001600160a01b0360406000205416151590565b1561477b565b613c4c86612d2c565b1580613eba575b80613eb2575b613e9a5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613ca4613c3d8960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a1613d346001600160a01b036060840151166001600160801b038084511681602086015116011690309033906147c6565b6001600160801b0360408201511680613e6a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb613e276001600160a01b03845116926001600160a01b03602086015116946001600160a01b0360608201511696613e5f613e3f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613dd38c6128e8565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e088015286019061283e565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613e94906001600160a01b036060850151166001600160a01b0361010086015151169033906147c6565b38613d48565b60248660405190630da9b01360e01b82526004820152fd5b506000613c59565b50801515613c53565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b613f158160e08601516138d2565b519060048601549168010000000000000000831015611eea5760018301806004890155831015612b8e5760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613b98565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614071906001600160801b0361406885886138d2565b51511690614362565b9364ffffffffff80604061408586856138d2565b510151169416808511156140a1575060018493019092916139e2565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff60406140ef846138c5565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116141e6575b816141d460209383612935565b810103126102c9576139689051613944565b3d91506141c7565b60009080825260056020526001600160a01b038060408420541692833314938415614233575b5050821561422157505090565b90915061422e3392612987565b161490565b60ff9294509060409181526008602052818120338252602052205416913880614214565b80600052600b6020526142706002604060002001612c68565b81600052600b602052604060002060ff600182015460a01c166000146142a357506001600160801b039150602001511690565b5460f81c6142b55750612c46906134fd565b612c4691506001600160801b0360408183511692015116906129c4565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611eea5761433892604052614831565b565b612c469061434781614257565b90600052600b60205260026040600020015460801c906129c4565b9190916001600160801b03808094169116019182116116d857565b64ffffffffff6143b2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614b01565b91808252600b6020526004604083200180541561443d5790829167ffffffffffffffff935261440f6020832054828452600b60205261440a6001600160801b03968760026040882001541696879360801c1690614bf1565b614c5f565b92831361442557505061442190614d49565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b60205260409081812082519361447885612918565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c161515610100880152610140614513600461450460028801612c68565b966101208b0197885201612c9c565b9701918783528087614525889a6138c5565b5101511693828288965b16106146045750916145b961440a928488816145be98976001600160801b039e8f61455b8b8a516138d2565b5151169d8a8f9b602061457867ffffffffffffffff928d516138d2565b5101511699848361458a8484516138d2565b51015116965081156145f8576145a8929350519060001901906138d2565b5101511680925b0316920316614b01565b614bf1565b9283136145d75750506145d18391614d49565b16011690565b5160200151929392831692841683101591506145f39050575090565b905090565b505050511680926145af565b8094986001600160801b03908161461c8c88516138d2565b51511601169801938282808a6146338989516138d2565b5101511661452f565b909291614647612c49565b936001600160801b03928381169182156147535767016345785d8a000080821161471c578085116146e5575061469185614682819386615875565b16946020890195865284615875565b1691846146a8604089019480865282875116614362565b1610156146cf576146c18491826146ca955116906129c4565b915116906129c4565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614766816128cc565b60008152600060208201526000604082015290565b1561478257565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611eea57614338926040525b6001600160a01b03169061489160405161484a816128e8565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af161488b61493e565b91615924565b805191821591848315614916575b5050509050156148ac5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91938180945001031261493a578201519081151582036130f157508038808461489f565b5080fd5b3d15614969573d9061494f82612957565b9161495d6040519384612935565b82523d6000602084013e565b606090565b9290803b15614af8576149d8916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c86523360048701521660248501526044840152608060648401526084830190612773565b03916000968791165af190829082614a97575b5050614a71576149f961493e565b80519081614a6c5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614af0575b81614ab460209383612935565b8101031261493a5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036130f157509038806149eb565b3d9150614aa7565b50505050600190565b600160ff1b808214908115614be7575b50614bbd576000811215614bb457614b3a816000035b6000841215614bad578360000390614d85565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614b765760001991181315614b705790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614d85565b614b3a81614b27565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614b11565b80614c0c5750614c0757670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614c59575080614c31575050670de0b6b3a764000090565b670de0b6b3a76400008114614c5557614c509061440a612c4693614e7f565b614fc1565b5090565b91505090565b600160ff1b808214908115614d3f575b50614d15576000811215614d0c57614c98816000035b6000841215614d05578360000390615875565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614cce5760001991181315614b705790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615875565b614c9881614c85565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c6f565b60008112614d545790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614e415782851015614e0557908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614e4f570490565b634e487b7160e01b600052601260045260246000fd5b8015614e4f576ec097ce7bc90715b34b9f10000000000590565b80600080831315614f9057670de0b6b3a764000092838112614f6d57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614f6157506706f05b59d3b20000905b848213614f355750505050500290565b808391020590671bc16d674ec80000821215614f54575b831d90614f25565b8091950194831d90614f4c565b93505093925050020290565b6000199392508015614e4f576ec097ce7bc90715b34b9f10000000000591614ea0565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614ff05768033dd1780914b971141981126135e257614fe790600003614fc1565b612c4690614e65565b680a688906bd8affffff811361584457670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615727575b66ff000000000000831661561f575b65ff0000000000831661551f575b64ff000000008316615427575b63ff0000008316615337575b62ff0000831661524f575b61ff00831661516f575b60ff8316615098575b02911c60bf031c90565b6080831661515d575b83831661514b575b60208316615139575b60108316615127575b60088316615115575b60048316615103575b600283166150f1575b600183161561508e576801000000000000000102831c61508e565b6801000000000000000102831c6150d6565b6801000000000000000302831c6150cd565b6801000000000000000602831c6150c4565b6801000000000000000b02831c6150bb565b6801000000000000001602831c6150b2565b6801000000000000002c02831c6150a9565b6801000000000000005902831c6150a1565b618000831661523d575b614000831661522b575b6120008316615219575b6110008316615207575b61080083166151f5575b61040083166151e3575b61020083166151d1575b61010083161561508557680100000000000000b102831c615085565b6801000000000000016302831c6151b5565b680100000000000002c602831c6151ab565b6801000000000000058c02831c6151a1565b68010000000000000b1702831c615197565b6801000000000000162e02831c61518d565b68010000000000002c5d02831c615183565b680100000000000058b902831c615179565b628000008316615325575b624000008316615313575b622000008316615301575b6210000083166152ef575b6208000083166152dd575b6204000083166152cb575b6202000083166152b9575b6201000083161561507b576801000000000000b17202831c61507b565b680100000000000162e402831c61529c565b6801000000000002c5c802831c615291565b68010000000000058b9102831c615286565b680100000000000b172102831c61527b565b68010000000000162e4302831c615270565b680100000000002c5c8602831c615265565b6801000000000058b90c02831c61525a565b63800000008316615415575b63400000008316615403575b632000000083166153f1575b631000000083166153df575b630800000083166153cd575b630400000083166153bb575b630200000083166153a9575b63010000008316156150705768010000000000b1721802831c615070565b6801000000000162e43002831c61538b565b68010000000002c5c86002831c61537f565b680100000000058b90c002831c615373565b6801000000000b17217f02831c615367565b680100000000162e42ff02831c61535b565b6801000000002c5c85fe02831c61534f565b68010000000058b90bfc02831c615343565b648000000000831661550d575b64400000000083166154fb575b64200000000083166154e9575b64100000000083166154d7575b64080000000083166154c5575b64040000000083166154b3575b64020000000083166154a1575b64010000000083161561506457680100000000b17217f802831c615064565b68010000000162e42ff102831c615482565b680100000002c5c85fe302831c615475565b6801000000058b90bfce02831c615468565b68010000000b17217fbb02831c61545b565b6801000000162e42fff002831c61544e565b68010000002c5c8601cc02831c615441565b680100000058b90c0b4902831c615434565b65800000000000831661560d575b6540000000000083166155fb575b6520000000000083166155e9575b6510000000000083166155d7575b6508000000000083166155c5575b6504000000000083166155b3575b6502000000000083166155a1575b65010000000000831615615057576801000000b17218355102831c615057565b680100000162e430e5a202831c615581565b6801000002c5c863b73f02831c615573565b68010000058b90cf1e6e02831c615565565b680100000b1721bcfc9a02831c615557565b68010000162e43f4f83102831c615549565b680100002c5c89d5ec6d02831c61553b565b6801000058b91b5bc9ae02831c61552d565b66800000000000008316615715575b66400000000000008316615703575b662000000000000083166156f1575b661000000000000083166156df575b660800000000000083166156cd575b660400000000000083166156bb575b660200000000000083166156a9575b66010000000000008316156150495768010000b17255775c0402831c615049565b6801000162e525ee054702831c615688565b68010002c5cc37da949202831c615679565b680100058ba01fb9f96d02831c61566a565b6801000b175effdc76ba02831c61565b565b680100162f3904051fa102831c61564c565b6801002c605e2e8cec5002831c61563d565b68010058c86da1c09ea202831c61562e565b6780000000000000008316615825575b6740000000000000008316615813575b6720000000000000008316615801575b67100000000000000083166157ef575b67080000000000000083166157dd575b67040000000000000083166157cb575b67020000000000000083166157b9575b67010000000000000083161561503a57680100b1afa5abcbed6102831c61503a565b68010163da9fb33356d802831c615797565b680102c9a3e778060ee702831c615787565b6801059b0d31585743ae02831c615777565b68010b5586cf9890f62a02831c615767565b6801172b83c7d517adce02831c615757565b6801306fe0a31b7152df02831c615747565b5077b504f333f9de648480000000000000000000000000000000615737565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461591357670de0b6b3a764000090818310156158dc57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b919290156159855750815115615938575090565b3b156159415790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156159985750805190602001fd5b6107809060405191829162461bcd60e51b835260206004840152602483019061277356fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003e757601f196001600160401b03601f62004e763881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a55600955604051614a5390816200042382396080518161393c0152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612fc45750806306fdde0314612f00578063081812fc14612ee1578063095ea7b314612d525780631400ecec14612cb25780631c1cdd4c14612c4d5780631e99d56914612c2f57806323b872dd14612c0557806339a73c0314612bc457806340e58ee514612926578063425d30dd1461290757806342842e0e146128b757806342966c681461272d5780634857501f146126a35780634869e12d146126685780635fe3b567146126415780636352211e146126225780636d0cee75146125cc57806370a082311461252357806375829def14612490578063780a82c8146124405780637cad6cd11461236f5780637de6b1db1461218f5780638659c27014611e6e578063894e9a0d14611c1a5780638bad38dd14611b9d5780638f69b99314611b015780639067b67714611aae57806395d89b411461199f57806396ce143114611880578063a22cb465146117af578063a2ffb89714611325578063a6202bf214611228578063a80fc071146111d6578063ab167ccc1461109d578063ad35efd41461103b578063b25645691461101c578063b88d4fde14610f92578063b8a3be6614610f5d578063b971302a14610f2d578063bc063e1a14610f0a578063bc2be1be14610eba578063c156a11d14610a74578063c87b56dd1461093a578063cc364f481461088c578063d4dbd20b1461083a578063d511609f146107ee578063d975dfed146107a2578063e985e9c51461074d578063ea5ead1914610727578063eac8f5b8146106be578063f590c17614610695578063f851a4401461066f5763fdd46d601461027357600080fd5b3461066c57606036600319011261066c5760043561028f6130f3565b610297613233565b61029f613932565b6102a883613326565b610654576102cc83600052600b6020526001600160a01b0360406000205416331490565b801592908380610644575b61062557848652602093600585526001600160a01b0391826040892054169080610619575b6105f35782841680156105c9576001600160801b03908187169182156105b1576103258a61431b565b818116841161057b5750918796959492918a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b888f9c989660408e6001926103c161038a6103738a613513565b9e8a8552600b89526002868620015460801c614343565b898452600b88526103bc6002868620019182906001600160801b036001600160801b031983549260801b169116179055565b613412565b906103dc818884015116928286818351169201511690613286565b16111561054d575b868152600b855220015416946103fb818c886142b3565b604051908152a48033141580610543575b6104ce575b50806104c4575b61044b575b847ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78789604051908152a180f35b1691823b156104c057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104a8575b80808061041d565b6104b19061316f565b6104bc5782386104a0565b8280fd5b8380fd5b50803b1515610418565b803b1561053f57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03861660448201526001600160801b0387166064820152879182908290608490829084905af1610527575b50610411565b6105309061316f565b61053b578538610521565b8580fd5b8680fd5b50803b151561040c565b868152600b8552818120838101600160c81b60ff60c81b1982541617905560ff60f01b1981541690556103e4565b60405163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b0390fd5b60248a6040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b606487848660405192632dcbf6b960e11b84526004840152336024840152166044820152fd5b508083851614156102fc565b60405163216caf0d60e01b815260048101869052336024820152604490fd5b5061064e8561398e565b156102d7565b60248360405190634a5541ef60e01b82526004820152fd5b80fd5b503461066c578060031936011261066c576001600160a01b036020915416604051908152f35b503461066c57602036600319011261066c5760206106b460043561354a565b6040519015158152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760016040836001600160a01b039360209552600b855220015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066c57604036600319011261066c576004356107446130f3565b6102978261431b565b503461066c57604036600319011261066c576107676130dd565b60406107716130f3565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b503461066c57602036600319011261066c5760ff6001604060043593848152600b60205220015460d01c1615610710576107dd60209161431b565b6001600160801b0360405191168152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408260029260209452600b845220015460801c604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760036040836001600160801b039360209552600b855220015416604051908152f35b503461066c57602036600319011261066c576004356108a96133f3565b50808252600b60205260ff600160408420015460d01c1615610710578160409160609352600b60205220600181549164ffffffffff918291015460a01c1690604051926108f5846131bd565b818160a01c16845260c81c166020830152604082015261093860405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b503461066c57602080600319360112610a64576004356109786109738260005260056020526001600160a01b0360406000205416151590565b61335d565b826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a685780936109e7575b50506109e36040519282849384528301906130b8565b0390f35b909192503d8082843e6109fa81846131f5565b8201918381840312610a645780519067ffffffffffffffff82116104bc570182601f82011215610a6457805191610a3083613217565b93610a3e60405195866131f5565b83855285848401011161066c575090610a5c91848085019101613095565b9038806109cd565b5080fd5b604051903d90823e3d90fd5b503461066c57604036600319011261066c57600435610a916130f3565b90610a9a613932565b808352602091600b835260ff600160408620015460d01c1615610ea357818452600583526001600160a01b038060408620541690813303610e8457610ade8461431b565b906001600160801b03808316908115918215610b04575b89610b01898989613797565b80f35b610b0c613932565b610b1588613326565b610e6c57610b3988600052600b6020526001600160a01b0360406000205416331490565b91821593848095610e5c575b610e3d57898c5260058b528560408d2054169380610e33575b610e0f5787156105c957610df757610b758961431b565b8181168311610dc5575091859493918a84610bfc8e9996610be58e6103bc600260408f610bba610ba486613513565b9e868352600b8c5284848420015460801c614343565b948152600b8a5220019182906001600160801b036001600160801b031983549260801b169116179055565b938401511692826040818351169201511690613286565b161115610d95575b898752600b8b52878a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8d88600160408d2001541694610c458186886142b3565b604051908152a48033141580610d8b575b610d1e575b5080610d14575b610ca1575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7610b0194604051858152a13880808080610af5565b16803b156104bc57604051636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b0392909216606483015282908290608490829084905af1610cfc575b8080610c67565b610d059061316f565b610d10578438610cf5565b8480fd5b50803b1515610c62565b803b1561053b57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03881660448201526001600160801b0386166064820152869182908290608490829084905af1610d77575b50610c5b565b610d809061316f565b610d10578438610d71565b50803b1515610c56565b898752600b8b526040872060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055610c04565b60405163287ecaef60e21b8152600481018b90526001600160801b038881166024830152919091166044820152606490fd5b6024896040519063d2aabcd960e01b82526004820152fd5b60648a8960405191632dcbf6b960e11b835260048301523360248301526044820152fd5b5083881415610b5e565b60405163216caf0d60e01b8152600481018b9052336024820152604490fd5b50610e668a61398e565b15610b45565b60248860405190634a5541ef60e01b82526004820152fd5b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b503461066c578060031936011261066c57602060405167016345785d8a00008152f35b503461066c57602036600319011261066c576020610f4c600435613513565b6001600160a01b0360405191168152f35b503461066c57602036600319011261066c5760ff600160406020936004358152600b855220015460d01c166040519015158152f35b503461066c57608036600319011261066c57610fac6130dd565b610fb46130f3565b906064359067ffffffffffffffff82116104c057366023830112156104c05781600401359284610fe385613217565b93610ff160405195866131f5565b8585523660248783010111610a645785610b019660246020930183880137850101526044359161347d565b503461066c57602036600319011261066c5760206106b4600435613446565b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105761107490613631565b60405190600581101561108957602092508152f35b602483634e487b7160e01b81526021600452fd5b503461066c5761014036600319011261066c576110b8613932565b6110c06133f3565b9064ffffffffff80421680845260c43582811681036111d15781018216602085015260e4359081831682036111d15701166040830152606435916001600160a01b039182841680940361066c57506084358015158091036111d15760a435908115158092036111d157602435948486168096036111d157600435958587168097036111d157604435906001600160801b0382168092036111d15760405197611167896131a0565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126111d157604051916111a1836131d9565b6101043591821682036111d157826111c99260209452610124358482015260e0820152613a72565b604051908152f35b600080fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760026040836001600160801b039360209552600b855220015416604051908152f35b503461066c57602036600319011261066c576112426130dd565b6001600160a01b03808354163381036112fc575081169081835260026020526001600160801b036040842054169081156112cb578161129c918486526002602052604086206001600160801b0319815416905533906142b3565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461066c57606036600319011261066c5767ffffffffffffffff6004358181116104bc5761135890369060040161313e565b916113616130f3565b9060449060443590811161053b5761137d90369060040161313e565b9094611387613932565b81810361177957865b81811061139b578780f35b6113a68183886133cd565b35906113b381858a6133cd565b356001600160801b03811681036111d1576113cc613932565b6113d583613326565b610654576113f983600052600b6020526001600160a01b0360406000205416331490565b80158080611769575b61062557848c5260056020526001600160a01b0360408d2054169180611756575b611729576001600160a01b038916156105c9576001600160801b038316156117115761144e8561431b565b6001600160801b0381166001600160801b038516116116df5750908b929161147586613513565b91868552600b806020526114c960026103bc61149a888360408c20015460801c614343565b918b8a528460205260408a20019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036114ed8160208401511692826040818351169201511690613286565b1611156116af575b8786526020526001600160a01b036001604087200154166115206001600160801b0386168d836142b3565b8b887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03604051946001600160801b038b1686521693a480331415806116a5575b611638575b508061162e575b6115b1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101611390565b6001600160a01b0381163b156104bc57604051636fd110e960e01b8152600481018690523360248201526001600160a01b038a811660448301526001600160801b03939093166064820152918391839160849183918591165af1611616575b8061157b565b61161f9061316f565b61162a578838611610565b8880fd5b50803b1515611576565b803b15610d1057604051636fd110e960e01b8152600481018890523360248201526001600160a01b038c1660448201526001600160801b0385166064820152859182908290608490829084905af1611691575b5061156f565b61169a9061316f565b6104c057833861168b565b50803b151561156a565b878652806020526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b1981541690556114f5565b60405163287ecaef60e21b8152600481018790526001600160801b038581166024830152919091166044820152606490fd5b6024856040519063d2aabcd960e01b82526004820152fd5b606485896001600160a01b038c60405193632dcbf6b960e11b855260048501523360248501521690820152fd5b50816001600160a01b038a161415611423565b506117738561398e565b15611402565b604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461066c57604036600319011261066c576117c96130dd565b602435908115158092036111d1576001600160a01b03169081331461183c5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b503461066c5761016036600319011261066c5761189b613932565b604051906118a8826131a0565b6118b06130dd565b82526118ba6130f3565b60208301526118c7613233565b60408301526001600160a01b039060643582811681036111d157606084015260843580151581036111d157608084015260a43580151581036111d15760a084015260603660c319011261066c5750604051611921816131bd565b64ffffffffff60c43581811681036111d157825260e43581811681036111d15760208301526101043590811681036111d157604082015260c08301526040610123193601126111d15760405191611977836131d9565b6101243591821682036111d157826111c99260209452610144358482015260e0820152613a72565b503461066c578060031936011261066c5760405190806004549160018360011c9260018516948515611aa4575b6020958686108114611a9057858852879493929187908215611a6e575050600114611a14575b5050611a00925003836131f5565b6109e36040519282849384528301906130b8565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b858310611a56575050611a00935082010138806119f2565b80548389018501528794508693909201918101611a3e565b9250935050611a0094915060ff191682840152151560051b82010138806119f2565b602483634e487b7160e01b81526022600452fd5b93607f16936119cc565b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057600160408364ffffffffff9360209552600b855220015460a01c16604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057611b3a90613631565b9060058210159081611b7b5760028314918215611b8f575b8215611b66575b6020836040519015158152f35b909150611b7b57506004602091143880611b59565b80634e487b7160e01b602492526021600452fd5b506003831491506000611b52565b503461066c57602036600319011261066c576004356001600160a01b03908181168091036104bc57818354163381036112fc575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b503461066c57602036600319011261066c57604051611c3881613183565b8181528160208201528160408201528160608201528160808201528160a08201528160c08201528160e08201528161010082015281610120820152610140611c7e6133f3565b9101526004358152600b60205260ff600160408320015460d01c1615611e56576004358152600b60205260408120611d57600260405192611cbe84613183565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a087015264ffffffffff8160a01c1660c0870152818160c81c16151560e0870152818160d01c16151561010087015260d81c16151561012085015201613412565b610140820152611d68600435613631565b6005811015611089579160026101a09314611e4b575b50610938610140604051926001600160a01b03815116845264ffffffffff602082015116602085015264ffffffffff60408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a085015264ffffffffff60c08201511660c085015260e0810151151560e0850152610100810151151561010085015261012081015115156101208501520151610140830190604090816001600160801b0391828151168552826020820151166020860152015116910152565b606082015238611d7e565b602460405162b8e7e760e51b81526004356004820152fd5b503461066c576020908160031936011261066c5760043567ffffffffffffffff8111610a6457611ea38391369060040161313e565b9190611ead613932565b83925b808410611ebb578480f35b611eca848284979596976133cd565b3594611ed4613932565b611edd86613326565b15611efa5760248660405190634a5541ef60e01b82526004820152fd5b611f038661354a565b61217757611f2786600052600b6020526001600160a01b0360406000205416331490565b1561215857611f358661357b565b95808552600b90818752611f4e60026040882001613412565b906001600160801b039283835116848b1610156121405781885280895260ff604089205460f01c161561212857611f9e8a858b611f9460409a9b9c9d9e83895116613286565b9601511690613286565b92828a52818b52868a20908b8b7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50845497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a1617865560038a821696871561210e575b01998516998a6001600160801b03198254161790556001600160a01b0380991698899360058652818e822054169889965260019d8e91200154169461204b8b85886142b3565b604080518a81526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78b604051858152a1813b6120af575b505050505001919093919293611eb0565b813b1561210a578994939192858094608493604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16120f6575b80808061209e565b6120ff9061316f565b610d105784876120ee565b8980fd5b60018101600160c81b60ff60c81b19825416179055612005565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b6024866040519063fe19f19f60e01b82526004820152fd5b503461066c57602080600319360112610a6457600435906121ae613932565b818352600b815260ff600160408520015460d01c1615610ea3576121d182613631565b600581101561235b57600481036121fa5760248360405190634a5541ef60e01b82526004820152fd5b6003810361221a576024836040519063fe19f19f60e01b82526004820152fd5b6002146121405761224182600052600b6020526001600160a01b0360406000205416331490565b1561233c57818352600b815260ff604084205460f01c161561212857818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b6122e4575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104bc57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612328575b806122b5565b6123319061316f565b6104bc578238612322565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602484634e487b7160e01b81526021600452fd5b503461066c57602036600319011261066c576004356001600160a01b03908181168091036104bc57818354163381036112fc5750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600954600019810190811161242c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c16156107105760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066c57602036600319011261066c576124aa6130dd565b9080546001600160a01b03808216933385036124fc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461066c57602036600319011261066c576001600160a01b036125456130dd565b168015612562578160409160209352600683522054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b503461066c57602036600319011261066c576001600160a01b0360406020926004356126116109738260005260056020526001600160a01b0360406000205416151590565b815260058452205416604051908152f35b503461066c57602036600319011261066c576020610f4c6004356133a8565b503461066c578060031936011261066c5760206001600160a01b0360015416604051908152f35b503461066c57602036600319011261066c5760ff6001604060043593848152600b60205220015460d01c1615610710576107dd6020916139f7565b503461066c57602036600319011261066c5760043590818152600b60205260ff600160408320015460d01c1615610ea357806126de83613631565b926005841015612719576002602094036126ff575b50506040519015158152f35b8152600b8352604090205460f01c60ff16905038806126f3565b602482634e487b7160e01b81526021600452fd5b503461066c57602036600319011261066c5760043561274a613932565b61275381613326565b15612886576127618161398e565b156128665761276f816133a8565b61277882613446565b15908161285e575b8161284b575b50612833576020816127b87ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7936133a8565b90808552600783526001600160a01b0360408620926001600160a01b03199384815416905516918286526006845260408620600019815401905581865260058452604086209081541690558085604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a180f35b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151538612786565b839150612780565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066c576128c636613109565b60405191602083019383851067ffffffffffffffff8611176128f157610b019460405285845261347d565b634e487b7160e01b600052604160045260246000fd5b503461066c57602036600319011261066c5760206106b4600435613326565b503461066c57602080600319360112610a645760043590612945613932565b61294e82613326565b1561296b5760248260405190634a5541ef60e01b82526004820152fd5b906129758161354a565b612bac5761299981600052600b6020526001600160a01b0360406000205416331490565b15612866576129a78161357b565b818452600b83526129bd60026040862001613412565b926001600160801b0391828551168382161015612b9457838652600b825260ff604087205460f01c1615612b7c5792827ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce783612a328784604097612a288d9b612add9b8e5116613286565b9b01511690613286565b92848852600b825287868120947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84161788556003858216988915612b62575b01948d169c858e6001600160801b0319819854161790556001600160a01b038094169b8c94600589526001818e892054169d8e98600b8c52200154169685886142b3565b604080518b81526001600160801b0392831660208201529290911690820152606090a4604051848152a1823b612b11578480f35b823b15610d10576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612b53575b81818080808480f35b612b5c9061316f565b38612b4a565b60018101600160c81b60ff60c81b19825416179055612a99565b602484604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b6024906040519063fe19f19f60e01b82526004820152fd5b503461066c57602036600319011261066c576001600160801b0360406020926001600160a01b03612bf36130dd565b16815260028452205416604051908152f35b503461066c57610b01612c1736613109565b91612c2a612c2584336136b8565b6132b5565b613797565b503461066c578060031936011261066c576020600954604051908152f35b503461066c57602036600319011261066c57600435808252600b60205260ff600160408420015460d01c161561071057612c8690613631565b906005821015611b7b5760208215838115612ca7575b506040519015158152f35b600191501482612c9c565b503461066c57602036600319011261066c5760043590818152600b60205260ff600160408320015460d01c1615610ea357602091604082828152600b85522060ff815460f01c1680612d40575b612d17575b50506001600160801b0360405191168152f35b612d3992506001600160801b036002612d33920154169161357b565b90613286565b3880612d04565b5060ff600182015460c81c1615612cff565b503461066c57604036600319011261066c57612d6c6130dd565b602435906001600160a01b038080612d83856133a8565b16921691808314612e7757803314908115612e56575b5015612dec57828452600760205260408420826001600160a01b0319825416179055612dc4836133a8565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050845260086020526040842033855260205260ff60408520541638612d99565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b503461066c57602036600319011261066c576020610f4c600435613249565b503461066c578060031936011261066c5760405190806003549160018360011c9260018516948515612fba575b6020958686108114611a9057858852879493929187908215611a6e575050600114612f60575050611a00925003836131f5565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b858310612fa2575050611a00935082010138806119f2565b80548389018501528794508693909201918101612f8a565b93607f1693612f2d565b905034610a64576020366003190112610a64576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104bc57602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561306b575b8115613041575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861303a565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613033565b60005b8381106130a85750506000910152565b8181015183820152602001613098565b906020916130d181518092818552858086019101613095565b601f01601f1916010190565b600435906001600160a01b03821682036111d157565b602435906001600160a01b03821682036111d157565b60609060031901126111d1576001600160a01b039060043582811681036111d1579160243590811681036111d1579060443590565b9181601f840112156111d15782359167ffffffffffffffff83116111d1576020808501948460051b0101116111d157565b67ffffffffffffffff81116128f157604052565b610160810190811067ffffffffffffffff8211176128f157604052565b610100810190811067ffffffffffffffff8211176128f157604052565b6060810190811067ffffffffffffffff8211176128f157604052565b6040810190811067ffffffffffffffff8211176128f157604052565b90601f8019910116810190811067ffffffffffffffff8211176128f157604052565b67ffffffffffffffff81116128f157601f01601f191660200190565b604435906001600160801b03821682036111d157565b61326c6109738260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161329f57565b634e487b7160e01b600052601160045260246000fd5b156132bc57565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260ff60016040600020015460c81c1690565b1561336457565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b03604060002054166133ca81151561335d565b90565b91908110156133dd5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190613400826131bd565b60006040838281528260208201520152565b9060405161341f816131bd565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260ff60016040600020015460d81c1690565b906134a1939291613491612c2584336136b8565b61349c838383613797565b61468c565b156134a857565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460d01c161561071057600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460d01c161561071057600052600b60205260406000205460f81c90565b600090808252600b6020526040822091825464ffffffffff42818360c81c16116136295780600186015460a01c169182421015613613576135c89394955060a01c1680910390420361481f565b90828152600b6020526001600160801b03926135ee8460026040852001541680946148ff565b9283116135fb5750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b505091505090565b80600052600b602052604060002060ff600182015460c81c16600014613658575050600490565b805460f81c6136b1575460a01c64ffffffffff1642106136ab5761367b8161357b565b90600052600b6020526001600160801b0380600260406000200154169116106000146136a657600190565b600290565b50600090565b5050600390565b906001600160a01b0380806136cc846133a8565b169316918383149384156136ff575b5083156136e9575b50505090565b6136f591929350613249565b16143880806136e3565b909350600052600860205260406000208260005260205260ff6040600020541692386136db565b1561372d57565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b906137c092916137a6836133a8565b916001600160a01b03948593848094169687911614613726565b16908115806138c9576137d284613446565b1590816138c0575b50806138b7575b61389f57918084926138217ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661381a856133a8565b1614613726565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b508315156137e1565b905015386137da565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396457565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b0380604084205416928333149384156139d3575b505082156139c157505090565b9091506139ce3392613249565b161490565b60ff92945090604091815260086020528181203382526020522054169138806139b4565b80600052600b602052613a106002604060002001613412565b81600052600b602052604060002060ff600182015460c81c16600014613a4357506001600160801b039150602001511690565b5460f81c613a5557506133ca9061357b565b6133ca91506001600160801b036040818351169201511690613286565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156142a757600090614273575b613af391506001600160801b0360408501511690602060e086015101519161435e565b916001600160801b0383511660c082015190156142495764ffffffffff815116602082019064ffffffffff8251169081811161420957505064ffffffffff604091511691019064ffffffffff82511690818110156141c957505064ffffffffff8042169151169081811015614189575050600954926001600160801b0381511660405190613b80826131bd565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff6020840151169064ffffffffff604085015116906080870151151560a088015115159364ffffffffff6001600160a01b038a511697511660405197613bef89613183565b88526020880152604087015260608601526000608086015260a085015260c0840152600060e0840152600161010084015261012083015261014082015284600052600b60205260406000206001600160a01b038251166001600160a01b0319825416178155613c8664ffffffffff602084015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b604082015181547eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b169078ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006080880151151560f81b169460c81b1691161717178155600181016001600160a01b0360a0840151166001600160a01b0319825416178155613d7d64ffffffffff60c085015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b60e083015181546101008501516101208601517fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921692151560c81b79ff00000000000000000000000000000000000000000000000000169290921791151560d01b7aff0000000000000000000000000000000000000000000000000000169190911790151560d81b7bff00000000000000000000000000000000000000000000000000000016179055610140909101518051602082015160801b6001600160801b03199081166001600160801b03928316176002850155926040906003019201511682825416179055600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b03602083015116801561414557613ef8613ef28660005260056020526001600160a01b0360406000205416151590565b1561449d565b613f0185613446565b158061413c575b80614134575b61411c5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613f59613ef28860005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905586600052600582526040600020816001600160a01b0319825416179055866040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4868152a1613fe96001600160a01b036060840151166001600160801b038084511681602086015116011690309033906144e8565b6001600160801b03604082015116806140ed575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140e46001600160a01b03606089015116976080810151151560a08201511515906140ae6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b614116906001600160a01b036060850151166001600160a01b0360e086015151169033906144e8565b38613ffd565b60248560405190630da9b01360e01b82526004820152fd5b506000613f0e565b50801515613f08565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f4c23297000000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161429f575b8161428d602093836131f5565b810103126111d157613af39051613ad0565b3d9150614280565b6040513d6000823e3d90fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff8411176128f15761431992604052614553565b565b6133ca90614328816139f7565b90600052600b60205260026040600020015460801c90613286565b9190916001600160801b038080941691160191821161329f57565b9092916143696133f3565b936001600160801b03928381169182156144755767016345785d8a000080821161443e5780851161440757506143b3856143a48193866148ff565b169460208901958652846148ff565b1691846143ca604089019480865282875116614343565b1610156143f1576143e38491826143ec95511690613286565b91511690613286565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614488816131bd565b60008152600060208201526000604082015290565b156144a457565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176128f157614319926040525b6001600160a01b0316906145b360405161456c816131d9565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16145ad61465c565b916149ae565b805191821591848315614638575b5050509050156145ce5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b919381809450010312610a645782015190811515820361066c5750803880846145c1565b3d15614687573d9061466d82613217565b9161467b60405193846131f5565b82523d6000602084013e565b606090565b9290803b15614816576146f6916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c865233600487015216602485015260448401526080606484015260848301906130b8565b03916000968791165af1908290826147b5575b505061478f5761471761465c565b8051908161478a5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d60201161480e575b816147d2602093836131f5565b81010312610a645751907fffffffff000000000000000000000000000000000000000000000000000000008216820361066c5750903880614709565b3d91506147c5565b50505050600190565b670de0b6b3a76400009160001983830992808302928380861095039480860395146148db578285101561489f57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156148e9570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461499d57670de0b6b3a7640000908183101561496657947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b91929015614a0f57508151156149c2575090565b3b156149cb5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015614a225750805190602001fd5b6105ad9060405191829162461bcd60e51b83526020600484015260248301906130b856fea164736f6c6343000817000a"; + hex"60a034620003e757601f196001600160401b03601f62004dd23881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516149af9081620004238239608051816138980152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f205750806306fdde0314612e5c578063081812fc14612e3d578063095ea7b314612cae5780631400ecec14612c0e5780631c1cdd4c14612ba95780631e99d56914612b8b57806323b872dd14612b6157806339a73c0314612b2057806340e58ee51461289a578063425d30dd1461287b57806342842e0e1461282b57806342966c68146126c1578063442675701461269a5780634857501f146126105780634869e12d146125d55780634cc55e111461217057806353b15727146120515780635fe3b5671461202a5780636352211e1461200b5780636d0cee7514611fb557806370a0823114611f0c57806375829def14611e79578063780a82c814611e295780637cad6cd114611d585780637de6b1db14611b485780638659c27014611831578063894e9a0d146115dd5780638bad38dd146115605780638f69b993146114c45780639067b6771461147157806395d89b4114611362578063a22cb46514611291578063a6202bf214611194578063a80fc07114611142578063ab167ccc14611008578063ad35efd414610fa6578063b256456914610f87578063b88d4fde14610efd578063b8a3be6614610ec8578063b971302a14610e98578063bc063e1a14610e75578063bc2be1be14610e25578063c156a11d14610a32578063c87b56dd146108f8578063cc364f481461084a578063d4dbd20b146107f8578063d511609f146107ac578063d975dfed14610760578063e985e9c51461070b578063ea5ead19146106e3578063eac8f5b81461067a578063f590c17614610651578063f851a4401461062b5763fdd46d601461027e57600080fd5b34610628576060366003190112610628576004359061029b61304f565b916102a461318f565b6102ac61388e565b6102b582613282565b610610576001600160a01b03908185169485156105e6576001600160801b03918281169384156105ce57858752602094600586528160408920541690818a1415806105be575b61059a5761030888614277565b868116821161056457508899610320899a989961346f565b968a8952600b8a5261037761033f87600260408d20015460801c61429f565b8c8b52600b8c52610372600260408d20019182906001600160801b036001600160801b031983549260801b169116179055565b61336e565b90610393818c84015116928260408183511692015116906131e2565b161115610534575b898852600b8952897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8a86600160408d20015416946103db818b8861420f565b604051908152a4803314158061052a575b6104b5575b508316928333141590816104aa575b50610434575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a657604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048e575b8080610406565b610497906130cb565b6104a2578238610487565b8280fd5b8380fd5b90503b151538610400565b803b1561052657604051636fd110e960e01b8152600481018990523360248201526001600160a01b03851660448201526001600160801b0384166064820152869182908290608490829084905af161050e575b506103f1565b610517906130cb565b610522578438610508565b8480fd5b8580fd5b50803b15156103ec565b898852600b89526040882060018101600160c81b60ff60c81b1982541617905560ff60f01b19815416905561039b565b60405163287ecaef60e21b8152600481018a90526001600160801b038681166024830152919091166044820152606490fd5b0390fd5b6064888b6040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8886138ea565b156102fb565b6024866040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248260405190634a5541ef60e01b82526004820152fd5b80fd5b50346106285780600319360112610628576001600160a01b036020915416604051908152f35b50346106285760203660031901126106285760206106706004356134a6565b6040519015158152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760016040836001600160a01b039360209552600b855220015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b5034610628576040366003190112610628576004359061070161304f565b916102a481614277565b503461062857604036600319011261062857610725613039565b604061072f61304f565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106285760203660031901126106285760ff6001604060043593848152600b60205220015460d01c16156106cc5761079b602091614277565b6001600160801b0360405191168152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408260029260209452600b845220015460801c604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760036040836001600160801b039360209552600b855220015416604051908152f35b50346106285760203660031901126106285760043561086761334f565b50808252600b60205260ff600160408420015460d01c16156106cc578160409160609352600b60205220600181549164ffffffffff918291015460a01c1690604051926108b3846130fc565b818160a01c16845260c81c16602083015260408201526108f660405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b503461062857602080600319360112610a22576004356109366109318260005260056020526001600160a01b0360406000205416151590565b6132df565b826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a265780936109a5575b50506109a1604051928284938452830190613014565b0390f35b909192503d8082843e6109b88184613151565b8201918381840312610a225780519067ffffffffffffffff82116104a2570182601f82011215610a22578051916109ee83613173565b936109fc6040519586613151565b838552858484010111610628575090610a1a91848085019101612ff1565b90388061098b565b5080fd5b604051903d90823e3d90fd5b503461062857604036600319011261062857600435610a4f61304f565b90610a5861388e565b808352602091600b835260ff600160408620015460d01c1615610e0e57818452600583526001600160a01b038060408620541690813303610def57610a9c84614277565b906001600160801b039081831680158015610ac1575b89610abe8989896136f3565b80f35b610ac961388e565b610ad288613282565b610dd75785156105e657610dbf57868952600588528160408a205416908186141580610daf575b610d8b57610b0688614277565b8481168211610d595750908994939291610b1f8961346f565b93898752600b8b52610b71610b3e87600260408b20015460801c61429f565b8b8952600b8d52610372600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b8d818d84015116928260408183511692015116906131e2565b161115610d29575b888652600b8a5286897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c86600160408c2001541694610bd681868861420f565b604051908152a48033141580610d1f575b610cb2575b50811690813314159081610ca7575b50610c3a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7610abe94604051858152a13880808080610ab2565b803b156104a257604051636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b0392909216606483015282908290608490829084905af1610c93575b80610c01565b610c9c906130cb565b610522578438610c8d565b90503b151538610bfb565b803b1561052257604051636fd110e960e01b8152600481018990523360248201526001600160a01b03871660448201526001600160801b0385166064820152859182908290608490829084905af1610d0b575b50610bec565b610d14906130cb565b6104a6578338610d05565b50803b1515610be7565b888652600b8a526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055610b95565b60405163287ecaef60e21b8152600481018a90526001600160801b038781166024830152919091166044820152606490fd5b606488876040519163b34359d360e01b835260048301523360248301526044820152fd5b50610db9886138ea565b15610af9565b6024876040519063d2aabcd960e01b82526004820152fd5b60248860405190634a5541ef60e01b82526004820152fd5b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610628578060031936011261062857602060405167016345785d8a00008152f35b5034610628576020366003190112610628576020610eb760043561346f565b6001600160a01b0360405191168152f35b50346106285760203660031901126106285760ff600160406020936004358152600b855220015460d01c166040519015158152f35b503461062857608036600319011261062857610f17613039565b610f1f61304f565b906064359067ffffffffffffffff82116104a657366023830112156104a65781600401359284610f4e85613173565b93610f5c6040519586613151565b8585523660248783010111610a225785610abe966024602093018388013785010152604435916133d9565b50346106285760203660031901126106285760206106706004356133a2565b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57610fdf9061358d565b604051906005811015610ff457602092508152f35b602483634e487b7160e01b81526021600452fd5b5034610628576101403660031901126106285761102361388e565b61102b61334f565b9064ffffffffff80421680845260c435828116810361113d5781018216602085015260e43590818316820361113d5701166040830152600435916001600160a01b039182841680940361113d576024359083821680920361113d57604435906001600160801b03821680920361113d576064359085821680920361062857506084359182151580930361113d5760a4359384151580950361113d57604051976110d3896130df565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261113d576040519161110d83613135565b61010435918216820361113d57826111359260209452610124358482015260e08201526139ce565b604051908152f35b600080fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760026040836001600160801b039360209552600b855220015416604051908152f35b5034610628576020366003190112610628576111ae613039565b6001600160a01b0380835416338103611268575081169081835260026020526001600160801b036040842054169081156112375781611208918486526002602052604086206001600160801b03198154169055339061420f565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610628576040366003190112610628576112ab613039565b6024359081151580920361113d576001600160a01b03169081331461131e5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b503461062857806003193601126106285760405190806004549160018360011c9260018516948515611467575b6020958686108114611453578588528794939291879082156114315750506001146113d7575b50506113c392500383613151565b6109a1604051928284938452830190613014565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8583106114195750506113c3935082010138806113b5565b80548389018501528794508693909201918101611401565b92509350506113c394915060ff191682840152151560051b82010138806113b5565b602483634e487b7160e01b81526022600452fd5b93607f169361138f565b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57600160408364ffffffffff9360209552600b855220015460a01c16604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc576114fd9061358d565b906005821015908161153e5760028314918215611552575b8215611529575b6020836040519015158152f35b90915061153e5750600460209114388061151c565b80634e487b7160e01b602492526021600452fd5b506003831491506000611515565b5034610628576020366003190112610628576004356001600160a01b03908181168091036104a25781835416338103611268575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b5034610628576020366003190112610628576040516115fb81613118565b8181528160208201528160408201528160608201528160808201528160a08201528160c08201528160e0820152816101008201528161012082015261014061164161334f565b9101526004358152600b60205260ff600160408320015460d01c1615611819576004358152600b6020526040812061171a60026040519261168184613118565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a087015264ffffffffff8160a01c1660c0870152818160c81c16151560e0870152818160d01c16151561010087015260d81c1615156101208501520161336e565b61014082015261172b60043561358d565b6005811015610ff4579160026101a0931461180e575b506108f6610140604051926001600160a01b03815116845264ffffffffff602082015116602085015264ffffffffff60408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a085015264ffffffffff60c08201511660c085015260e0810151151560e0850152610100810151151561010085015261012081015115156101208501520151610140830190604090816001600160801b0391828151168552826020820151166020860152015116910152565b606082015238611741565b602460405162b8e7e760e51b81526004356004820152fd5b503461062857602080600319360112610a225760043567ffffffffffffffff81116104a25761186490369060040161309a565b919061186e61388e565b83925b80841061187c578480f35b6118878482846132b9565b359361189161388e565b61189a85613282565b156118b75760248560405190634a5541ef60e01b82526004820152fd5b909192936118c4816134a6565b611b30576118e881600052600b6020526001600160a01b0360406000205416331490565b15611b10576118f6816134d7565b90808752600b9081875261190f600260408a200161336e565b916001600160801b0393848451168582161015611af857828a5281895260ff60408b205460f01c1615611ae0579061195e82868b6119548897968f9a809a51166131e2565b96015116906131e2565b91808652818a5260408620938a8554600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82161787556003888716978815611ac6575b0197831697886001600160801b03198254161790557f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506001600160a01b03809216968792600585528060408d20541697889552600160408d2001541694611a0b8b858861420f565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a6f575b505050505050600101929190611871565b813b1561052657856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611ab2575b80808080611a5e565b611abb906130cb565b610522578438611aa9565b60018101600160c81b60ff60c81b198254161790556119a3565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b503461062857602080600319360112610a225760043590611b6761388e565b818352600b815260ff600160408520015460d01c1615610e0e57611b8a8261358d565b6005811015611d445760048103611bb35760248360405190634a5541ef60e01b82526004820152fd5b60038103611bd3576024836040519063fe19f19f60e01b82526004820152fd5b600214611d2c57611bfa82600052600b6020526001600160a01b0360406000205416331490565b15611d0d57818352600b815260ff604084205460f01c1615611cf557818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b611c9d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a257816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611ce1575b80611c6e565b611cea906130cb565b6104a2578238611cdb565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b5034610628576020366003190112610628576004356001600160a01b03908181168091036104a257818354163381036112685750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101908111611e155760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461062857602036600319011261062857611e93613039565b9080546001600160a01b0380821693338503611ee5576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610628576020366003190112610628576001600160a01b03611f2e613039565b168015611f4b578160409160209352600683522054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b5034610628576020366003190112610628576001600160a01b036040602092600435611ffa6109318260005260056020526001600160a01b0360406000205416151590565b815260058452205416604051908152f35b5034610628576020366003190112610628576020610eb760043561332a565b503461062857806003193601126106285760206001600160a01b0360015416604051908152f35b5034610628576101603660031901126106285761206c61388e565b60405190612079826130df565b612081613039565b825261208b61304f565b602083015261209861318f565b60408301526001600160a01b0390606435828116810361113d576060840152608435801515810361113d57608084015260a435801515810361113d5760a084015260603660c319011261062857506040516120f2816130fc565b64ffffffffff60c435818116810361113d57825260e435818116810361113d57602083015261010435908116810361113d57604082015260c083015260406101231936011261113d576040519161214883613135565b61012435918216820361113d57826111359260209452610144358482015260e08201526139ce565b50346106285760403660031901126106285767ffffffffffffffff6004358181116104a2576121a390369060040161309a565b90916024359081116104a6576121bd90369060040161309a565b6121c561388e565b80830361259e57845b8381106121d9578580f35b6121e48185876132b9565b35906121f18186886132b9565b35875260056020526001600160a01b036040882054166122128285876132b9565b35906001600160801b038216820361113d5761222c61388e565b61223584613282565b6125865780156105e6576001600160801b0382161561256e5783895260056020526001600160a01b0360408a20541691828214158061255e575b61253a5761227c85614277565b6001600160801b0381166001600160801b0383161161250a5750908992916122a38661346f565b92868552600b806020526122f760026103726122c8868360408c20015460801c61429f565b918b8a528460205260408a20019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361231b81602084015116928260408183511692015116906131e2565b1611156124da575b8786526020526001600160a01b0360016040872001541661234e6001600160801b038416858361420f565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806124d0575b612463575b506001600160a01b03831692833314159081612458575b506123e6575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016121ce565b823b156104a657604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612440575b80806123af565b612449906130cb565b612454578638612439565b8680fd5b90503b1515386123a9565b803b1561052257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b0383166064820152859182908290608490829084905af16124bc575b50612392565b6124c5906130cb565b6104a65783386124b6565b50803b151561238d565b878652806020526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055612323565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b50612568856138ea565b1561226f565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106285760203660031901126106285760ff6001604060043593848152600b60205220015460d01c16156106cc5761079b602091613953565b50346106285760203660031901126106285760043590818152600b60205260ff600160408320015460d01c1615610e0e578061264b8361358d565b9260058410156126865760026020940361266c575b50506040519015158152f35b8152600b8352604090205460f01c60ff1690503880612660565b602482634e487b7160e01b81526021600452fd5b503461062857806003193601126106285760206001600160a01b03600a5416604051908152f35b5034610628576020366003190112610628576004356126de61388e565b6126e781613282565b156127fa576126f5816138ea565b15611b10576127038161332a565b61270c826133a2565b1590816127f2575b816127df575b506127c75760208161274c7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79361332a565b90808552600783526001600160a01b0360408620926001600160a01b03199384815416905516918286526006845260408620600019815401905581865260058452604086209081541690558085604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a180f35b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b0391501615153861271a565b839150612714565b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106285761283a36613065565b60405191602083019383851067ffffffffffffffff86111761286557610abe946040528584526133d9565b634e487b7160e01b600052604160045260246000fd5b5034610628576020366003190112610628576020610670600435613282565b503461062857602080600319360112610a2257600435906128b961388e565b6128c282613282565b156128df5760248260405190634a5541ef60e01b82526004820152fd5b906128e9816134a6565b611b305761290d81600052600b6020526001600160a01b0360406000205416331490565b15611b105761291b816134d7565b818452600b83526129316002604086200161336e565b926001600160801b0391828551168382161015612b0857838652600b825260ff604087205460f01c1615612af05792827ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7836129a6878460409761299c8d9b612a519b8e51166131e2565b9b015116906131e2565b92848852600b825287868120947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84161788556003858216988915612ad6575b01948d169c858e6001600160801b0319819854161790556001600160a01b038094169b8c94600589526001818e892054169d8e98600b8c522001541696858861420f565b604080518b81526001600160801b0392831660208201529290911690820152606090a4604051848152a1823b612a85578480f35b823b15610522576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612ac7575b81818080808480f35b612ad0906130cb565b38612abe565b60018101600160c81b60ff60c81b19825416179055612a0d565b602484604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b5034610628576020366003190112610628576001600160801b0360406020926001600160a01b03612b4f613039565b16815260028452205416604051908152f35b503461062857610abe612b7336613065565b91612b86612b818433613614565b613211565b6136f3565b50346106285780600319360112610628576020600954604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57612be29061358d565b90600582101561153e5760208215838115612c03575b506040519015158152f35b600191501482612bf8565b50346106285760203660031901126106285760043590818152600b60205260ff600160408320015460d01c1615610e0e57602091604082828152600b85522060ff815460f01c1680612c9c575b612c73575b50506001600160801b0360405191168152f35b612c9592506001600160801b036002612c8f92015416916134d7565b906131e2565b3880612c60565b5060ff600182015460c81c1615612c5b565b503461062857604036600319011261062857612cc8613039565b602435906001600160a01b038080612cdf8561332a565b16921691808314612dd357803314908115612db2575b5015612d4857828452600760205260408420826001600160a01b0319825416179055612d208361332a565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050845260086020526040842033855260205260ff60408520541638612cf5565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b5034610628576020366003190112610628576020610eb76004356131a5565b503461062857806003193601126106285760405190806003549160018360011c9260018516948515612f16575b602095868610811461145357858852879493929187908215611431575050600114612ebc5750506113c392500383613151565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b858310612efe5750506113c3935082010138806113b5565b80548389018501528794508693909201918101612ee6565b93607f1693612e89565b905034610a22576020366003190112610a22576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a257602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115612fc7575b8115612f9d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612f96565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612f8f565b60005b8381106130045750506000910152565b8181015183820152602001612ff4565b9060209161302d81518092818552858086019101612ff1565b601f01601f1916010190565b600435906001600160a01b038216820361113d57565b602435906001600160a01b038216820361113d57565b606090600319011261113d576001600160a01b0390600435828116810361113d5791602435908116810361113d579060443590565b9181601f8401121561113d5782359167ffffffffffffffff831161113d576020808501948460051b01011161113d57565b67ffffffffffffffff811161286557604052565b610100810190811067ffffffffffffffff82111761286557604052565b6060810190811067ffffffffffffffff82111761286557604052565b610160810190811067ffffffffffffffff82111761286557604052565b6040810190811067ffffffffffffffff82111761286557604052565b90601f8019910116810190811067ffffffffffffffff82111761286557604052565b67ffffffffffffffff811161286557601f01601f191660200190565b604435906001600160801b038216820361113d57565b6131c86109318260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116131fb57565b634e487b7160e01b600052601160045260246000fd5b1561321857565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260ff60016040600020015460c81c1690565b91908110156132c95760051b0190565b634e487b7160e01b600052603260045260246000fd5b156132e657565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b036040600020541661334c8115156132df565b90565b6040519061335c826130fc565b60006040838281528260208201520152565b9060405161337b816130fc565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260ff60016040600020015460d81c1690565b906133fd9392916133ed612b818433613614565b6133f88383836136f3565b6145e8565b1561340457565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260406000205460f81c90565b600090808252600b6020526040822091825464ffffffffff42818360c81c16116135855780600186015460a01c16918242101561356f576135249394955060a01c1680910390420361477b565b90828152600b6020526001600160801b039261354a84600260408520015416809461485b565b9283116135575750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b505091505090565b80600052600b602052604060002060ff600182015460c81c166000146135b4575050600490565b805460f81c61360d575460a01c64ffffffffff164210613607576135d7816134d7565b90600052600b6020526001600160801b03806002604060002001541691161060001461360257600190565b600290565b50600090565b5050600390565b906001600160a01b0380806136288461332a565b1693169183831493841561365b575b508315613645575b50505090565b613651919293506131a5565b161438808061363f565b909350600052600860205260406000208260005260205260ff604060002054169238613637565b1561368957565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b9061371c92916137028361332a565b916001600160a01b03948593848094169687911614613682565b16908115806138255761372e846133a2565b15908161381c575b5080613813575b6137fb579180849261377d7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7966020966137768561332a565b1614613682565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b5083151561373d565b90501538613736565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036138c057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b03806040842054169283331493841561392f575b5050821561391d57505090565b90915061392a33926131a5565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613910565b80600052600b60205261396c600260406000200161336e565b81600052600b602052604060002060ff600182015460c81c1660001461399f57506001600160801b039150602001511690565b5460f81c6139b1575061334c906134d7565b61334c91506001600160801b0360408183511692015116906131e2565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa8015614203576000906141cf575b613a4f91506001600160801b0360408501511690602060e08601510151916142ba565b916001600160801b0383511660c082015190156141a55764ffffffffff815116602082019064ffffffffff8251169081811161416557505064ffffffffff604091511691019064ffffffffff825116908181101561412557505064ffffffffff80421691511690818110156140e5575050600954926001600160801b0381511660405190613adc826130fc565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff6020840151169064ffffffffff604085015116906080870151151560a088015115159364ffffffffff6001600160a01b038a511697511660405197613b4b89613118565b88526020880152604087015260608601526000608086015260a085015260c0840152600060e0840152600161010084015261012083015261014082015284600052600b60205260406000206001600160a01b038251166001600160a01b0319825416178155613be264ffffffffff602084015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b604082015181547eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b169078ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006080880151151560f81b169460c81b1691161717178155600181016001600160a01b0360a0840151166001600160a01b0319825416178155613cd964ffffffffff60c085015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b60e083015181546101008501516101208601517fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921692151560c81b79ff00000000000000000000000000000000000000000000000000169290921791151560d01b7aff0000000000000000000000000000000000000000000000000000169190911790151560d81b7bff00000000000000000000000000000000000000000000000000000016179055610140909101518051602082015160801b6001600160801b03199081166001600160801b03928316176002850155926040906003019201511682825416179055600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b0360208301511680156140a157613e54613e4e8660005260056020526001600160a01b0360406000205416151590565b156143f9565b613e5d856133a2565b1580614098575b80614090575b6140785760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613eb5613e4e8860005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905586600052600582526040600020816001600160a01b0319825416179055866040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4868152a1613f456001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614444565b6001600160801b0360408201511680614049575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140406001600160a01b03606089015116976080810151151560a082015115159061400a6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b614072906001600160a01b036060850151166001600160a01b0360e08601515116903390614444565b38613f59565b60248560405190630da9b01360e01b82526004820152fd5b506000613e6a565b50801515613e64565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f4c23297000000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116141fb575b816141e960209383613151565b8101031261113d57613a4f9051613a2c565b3d91506141dc565b6040513d6000823e3d90fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff84111761286557614275926040526144af565b565b61334c9061428481613953565b90600052600b60205260026040600020015460801c906131e2565b9190916001600160801b03808094169116019182116131fb57565b9092916142c561334f565b936001600160801b03928381169182156143d15767016345785d8a000080821161439a57808511614363575061430f8561430081938661485b565b1694602089019586528461485b565b16918461432660408901948086528287511661429f565b16101561434d5761433f849182614348955116906131e2565b915116906131e2565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516143e4816130fc565b60008152600060208201526000604082015290565b1561440057565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761286557614275926040525b6001600160a01b03169061450f6040516144c881613135565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16145096145b8565b9161490a565b805191821591848315614594575b50505090501561452a5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b919381809450010312610a225782015190811515820361062857508038808461451d565b3d156145e3573d906145c982613173565b916145d76040519384613151565b82523d6000602084013e565b606090565b9290803b1561477257614652916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c86523360048701521660248501526044840152608060648401526084830190613014565b03916000968791165af190829082614711575b50506146eb576146736145b8565b805190816146e65760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d60201161476a575b8161472e60209383613151565b81010312610a225751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106285750903880614665565b3d9150614721565b50505050600190565b670de0b6b3a764000091600019838309928083029283808610950394808603951461483757828510156147fb57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614845570490565b634e487b7160e01b600052601260045260246000fd5b909190600019838209838202918280831092039180830392146148f957670de0b6b3a764000090818310156148c257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9192901561496b575081511561491e575090565b3b156149275790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501561497e5750805190602001fd5b6105969060405191829162461bcd60e51b835260206004840152602483019061301456fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615dcc90816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346142f85760403660031901126142f8576001600160a01b0360043516600435036142f857610056608061486e565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614946565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916147dd575b506001600160a01b03610117911680608052614b39565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614305576fffffffffffffffffffffffffffffffff916000916147be575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561430557600090614781575b6101e59150614c86565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561430557600091614752575b5060c0516fffffffffffffffffffffffffffffffff16801561473c576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614d82565b610120608001526040514660208201526bffffffffffffffffffffffff1960043560601b16604082015260243560548201526054815280608081011067ffffffffffffffff60808301111761431157608081016040526020815191012061041a602963ffffffff61032e6103078261016861ffff8860101c1606166155e2565b91601e604660ff6103248460146050848d60081c160601166155e2565b98160601166155e2565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261036e815180926020602488019101614826565b83017f2c0000000000000000000000000000000000000000000000000000000000000060248201526103aa825180936020602585019101614826565b017f252c00000000000000000000000000000000000000000000000000000000000060258201526103e5825180936020602785019101614826565b017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826148df565b6104526fffffffffffffffffffffffffffffffff6040608001511660ff61044b6001600160a01b0360805116614f69565b16906150d2565b6104666001600160a01b0360805116614946565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143055760249160009161471d575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa801561430557610528926000916146ee575b5064ffffffffff809116911661541d565b61012051610180519092916105b2602161054f60646105488187066158c3565b95046155e2565b6040519481610568879351809260208087019101614826565b820161057d8251809360208085019101614826565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836148df565b610100608001519260c060800151956101206080015197604051996105d68b61486e565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106a660c08401518451906159cf565b906109b361015c604051926106ba846148c3565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526107236040516106f38161488b565b60009052855160208701207fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4701490565b156146e6576090945b610735866155e2565b916040519586938493661e339034b21e9160c91b60208601526109818351958692610767846027840160208901614826565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107ae8551809660206042888701019101614826565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108b491889160f990910190602001614826565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094f91899161015190910190602001614826565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614826565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826148df565b6101008301526101208201526028610100830151604051906109d48261488b565b60008252610c7a61015c604051926109eb846148c3565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b610a2782615d49565b808211156146de5750945b610a3d8787016155e2565b91604051958693661e339034b21e9160c91b60208601528151610a67816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610aaa825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ba682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c3582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610c5c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101845201826148df565b610160840152016101808201526028602083015160405190610c9b8261488b565b60008252610ce561015c60405192610cb2846148c3565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b835201602082015261102060808301516030604051610d038161488b565b60008152610faa61015c60405194610d1a866148c3565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d4d86615ccb565b610d5682615d49565b808211156146d65750935b610d6d602886016155e2565b91604051978893661e339034b21e9160c91b60208601528151610d97816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dda825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ed682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f6582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610f8c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101865201846148df565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615068565b6060820152604051908161010081011067ffffffffffffffff6101008401111761431157610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161010084015191606081015194604051611176816148a7565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051966111d38861486e565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614311576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761431157611cb1611d129160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611868615996565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d0d60d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161199a60b88660208501936118da81605e840187614826565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261193f825180936020609385019101614826565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866148df565b6119a2615996565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a0881606b8a0184614826565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a4d825180936020608e85019101614826565b019082608e830152611a9160a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896148df565b611bd7610108611a9f615996565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b2b815180926020607387019101614826565b8201908760738301526076820152875190611b4a826096830188614826565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6148df565b611bdf615996565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614826565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cf382518093602060c485019101614826565b019160c483015260c78201520360b88101875201856148df565b615068565b92611d32611d1e614c14565b896020815191012090602081519101201490565b9788156146ad575b506040518060c081011067ffffffffffffffff60c0830111176143115760c08101604052609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614311576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146144885760405161218c8161488b565b60008152995b1561432757604051806101e081011067ffffffffffffffff6101e083011117614311576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761431157613b9f9c612e5a6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f2b9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612df68151809260208a8c019101614826565b8701612e0b8251809360208a85019101614826565b01612e1f8251809360208985019101614826565b01612e338251809360208885019101614826565b01612e478251809360208785019101614826565b01918201520360168101865201846148df565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e9f6026998260208c9451948593019101614826565b8901612eb48251809360208c85019101614826565b01612ec88251809360208b85019101614826565b01612edc8251809360208a85019101614826565b01612ef08251809360208985019101614826565b01612f048251809360208885019101614826565b01612f188251809360208785019101614826565b019182015203600d8101895201876148df565b6137be604c60e08301516101208401519361351a61314d6060604084015193015196612f578186615c0f565b9461314861012b604051612f6a816148c3565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fd4815180926020603787019101614826565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015282519261311891849161012090910190602001614826565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876148df565b615c0f565b9561332c61012b604051613160816148c3565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131ca815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261330782518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886148df565b6133368184615c77565b9261351561012b604051613349816148c3565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526133b3815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134f082518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856148df565b615c77565b906136f961012b60405161352d816148c3565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613597815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136d482518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836148df565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261375f815180926020604589019101614826565b8401613775825180936020604585019101614826565b0161378a825180936020604585019101614826565b0161379f825180936020604585019101614826565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826148df565b613a9e61019a6101408401516101a0850151906137ff6137f96137f36137ed60e060408b01519a0151946155e2565b946155e2565b976155e2565b916155e2565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061399a815180926020858a019101614826565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d2200000000000000000061013288015261014996613a048251809360208b85019101614826565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a478251809360208985019101614826565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a8a8251809360208785019101614826565b01918201520361017a8101855201836148df565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b2a815180926020607b89019101614826565b8401613b40825180936020607b85019101614826565b01613b55825180936020607b85019101614826565b01613b6a825180936020607b85019101614826565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826148df565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916142ba575b6142b661424f614154614245609487613d3b6089613c198a614946565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613c60815180926020604088019101614826565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613cc5825180936020606385019101614826565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d06825180936020608685019101614826565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826148df565b6101a05160a05161403e61017e613d536024356155e2565b9360a060800151613d6e6001600160a01b0360805116614946565b90604051968793613f2b60208601987f54686973204e465420726570726573656e74732061207061796d656e742073748a527f7265616d20696e2061205361626c696572205632200000000000000000000000604088015282516020840190613ddb8160558b0184614826565b8801947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613e658260b183018a614826565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ea082518093602060c385019101614826565b01613ed97f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614826565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613f1782518093602060d185019101614826565b019260d184015251809360d5840190614826565b019060d5820152613f4682518093602060df85019101614826565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560e38201527f204e4654206d616b657320746865206e6577206f776e657220746865207265636101038201527f697069656e74206f66207468652073747265616d2e205468652066756e6473206101238201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e206101438201527f666f72207468652070726576696f757320726563697069656e742e00000000006101638201520361015e8101855201836148df565b6101a051906141af6140516024356155e2565b916140d0602d604051809560208201976a029b0b13634b2b9102b19160ad1b8952614086815180926020602b87019101614826565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140c18251809360208785019101614826565b0103600d8101865201846148df565b610160516140dd90615733565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a015261411e815180926020602e8d019101614826565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614826565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614826565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614210825180936020609285019101614826565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826148df565b60e0819052615733565b6142a2603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142928151809260208686019101614826565b810103601d8101845201826148df565b604051918291602083526020830190614849565b0390f35b90506020813d6020116142fd575b816142d5602093836148df565b810103126142f85751906001600160a01b03821682036142f85790614154613bfc565b600080fd5b3d91506142c8565b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761431157610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123df565b604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612192565b6146cf9198506146bb614c4d565b906020815191012090602081519101201490565b9638611d3a565b905093610d61565b905094610a32565b60d09461072c565b614710915060203d602011614716575b61470881836148df565b810190614929565b38610517565b503d6146fe565b614736915060203d6020116147165761470881836148df565b386104c1565b634e487b7160e01b600052601260045260246000fd5b614774915060203d60201161477a575b61476c81836148df565b810190614901565b3861023f565b503d614762565b506020813d6020116147b6575b8161479b602093836148df565b810103126142f8575160058110156142f8576101e5906101db565b3d915061478e565b6147d7915060203d60201161477a5761476c81836148df565b38610181565b90506020813d60201161481e575b816147f8602093836148df565b810103126142f857516001600160a01b03811681036142f8576001600160a01b03610100565b3d91506147eb565b60005b8381106148395750506000910152565b8181015183820152602001614829565b9060209161486281518092818552858086019101614826565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761431157604052565b6020810190811067ffffffffffffffff82111761431157604052565b6060810190811067ffffffffffffffff82111761431157604052565b6040810190811067ffffffffffffffff82111761431157604052565b90601f8019910116810190811067ffffffffffffffff82111761431157604052565b908160209103126142f857516fffffffffffffffffffffffffffffffff811681036142f85790565b908160209103126142f8575164ffffffffff811681036142f85790565b6001600160a01b03166040519061495c826148a7565b602a8252602082016040368237825115614a755760309053815160019060011015614a7557607860218401536029905b8082116149fa57505061499c5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b9091600f81166010811015614a60577f3031323334353637383961626364656600000000000000000000000000000000901a614a3684866158b2565b5360041c918015614a4b57600019019061498c565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161431157601f01601f191660200190565b3d15614ad2573d90614ab882614a8b565b91614ac660405193846148df565b82523d6000602084013e565b606090565b6020818303126142f85780519067ffffffffffffffff82116142f8570181601f820112156142f8578051614b0a81614a8b565b92614b1860405194856148df565b818452602082840101116142f857614b369160208085019101614826565b90565b6000809160405160208101906395d89b4160e01b825260048152614b5c816148c3565b51915afa614b68614aa7565b90158015614c08575b614bce5780602080614b8893518301019101614ad7565b601e815111600014614b365750604051614ba1816148c3565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614bdb816148c3565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b71565b60405190614c21826148c3565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614c5a826148c3565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614d6c5760048103614ca05750614b36614c4d565b60038103614ce25750604051614cb5816148c3565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d245750604051614cf7816148c3565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d3357614b36614c14565b604051614d3f816148c3565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660409081516395d89b4160e01b8152600081600481855afa908115614f5e57600091614f3b575b50614e178351614dc1816148c3565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020918201528251908301207fc66b376a19264d832c1bc254000c18944ca5aa57ed50f4ea637c4da424d4c3bb1490565b15614e5557505051614e28816148c3565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b614eb98351614e63816148c3565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020918201528251908301207f6ab655856fa5352de8c05542b1937ac63c59342da992602767c02734cc5391651490565b15614ef757505051614eca816148c3565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b614f379083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614849565b0390fd5b614f5891503d806000833e614f5081836148df565b810190614ad7565b38614db2565b83513d6000823e3d90fd5b60405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614fa1816148c3565b6000928392839251915afa614fb4614aa7565b9080614feb575b15614fe757602081805181010312614fe357602001519060ff82168203614fe0575090565b80fd5b5080fd5b5090565b506020815114614fbb565b60405190615003826148c3565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061503c826148c3565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906150d092949360405195869260209461508a81518092888089019101614826565b840161509e82518093888085019101614826565b016150b182518093878085019101614826565b016150c482518093868085019101614826565b010380855201836148df565b565b80156153e257600091806153bd575090505b600190808281101561514e575050506150fb61502f565b614b36602260405183615118829551809260208086019101614826565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826148df565b66038d7ea4c6800011156153605760409081519060a0820182811067ffffffffffffffff821117614311578084526151858161488b565b600081528252825190615197826148c3565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516151d1816148c3565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615208816148c3565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615240816148c3565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615334575b50845194615287866148c3565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b8281106153215750505050615302615308917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526152fd866148c3565b6155e2565b916158c3565b916005851015614a7557614b369460051b015192615068565b81810184015188820185015283016152b8565b9591926103e89081851061535757508680916064600a8704069504930196615275565b9392965061527a565b505061536a614ff6565b614b36602860405183615387829551809260208086019101614826565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826148df565b600a0a9182156153ce5750046150e4565b80634e487b7160e01b602492526012600452fd5b50506040516153f0816148c3565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b6201518091030480615485575061543261502f565b614b3660266040518361544f829551809260208086019101614826565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826148df565b61270f8111615554576001810361551157614b3660206154d96040516154aa816148c3565b600481527f204461790000000000000000000000000000000000000000000000000000000083820152936155e2565b60405193816154f18693518092868087019101614826565b820161550582518093868085019101614826565b010380845201826148df565b614b3660206154d9604051615525816148c3565b600581527f204461797300000000000000000000000000000000000000000000000000000083820152936155e2565b5061555d614ff6565b614b36602a6040518361557a829551809260208086019101614826565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826148df565b906155ba82614a8b565b6155c760405191826148df565b82815280926155d8601f1991614a8b565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615725575b506d04ee2d6d415b85acef810000000080831015615716575b50662386f26fc1000080831015615707575b506305f5e100808310156156f8575b50612710808310156156e9575b5060648210156156d9575b600a809210156156cf575b60019081602161567a600187016155b0565b95860101905b61568c575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156156ca57919082615680565b615685565b9160010191615668565b919060646002910491019161565d565b60049193920491019138615652565b60089193920491019138615645565b60109193920491019138615636565b60209193920491019138615624565b60409350810491503861560b565b80511561589e57604051615746816148a7565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116158885760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103615888576157e5906002959492951b6155b0565b936020850193839284518501935b84811061583557505050505060039051068060011461582257600214615817575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151868201530195939291906157f3565b634e487b7160e01b600052601160045260246000fd5b506040516158ab8161488b565b6000815290565b908151811015614a75570160200190565b806158d557506040516158ab8161488b565b600a81101561593a576158e7906155e2565b614b36602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261592a8151809260208686019101614826565b81010360028101845201826148df565b615943906155e2565b614b36602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159868151809260208686019101614826565b81010360018101845201826148df565b604051906159a3826148c3565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615c01576159dd615996565b9061271090810390811161588857614b36916159fb610136926155e2565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615a87815180926020605788019101614826565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615b0f82518093602060a785019101614826565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615b7082518093602060d585019101614826565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826148df565b50506040516158ab8161488b565b60306150d0919392936040519481615c31879351809260208087019101614826565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615c688251809360208785019101614826565b010360108101855201836148df565b60256150d0919392936040519481615c99879351809260208087019101614826565b820164010714051160dd1b6020820152615cbc8251809360208785019101614826565b010360058101855201836148df565b60009080518015615d4157906000916000915b818310615cf057505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615d2387856158b2565b511614615d39575b600d01936001019190615cde565b849350615d2b565b505050600090565b60009080518015615d4157906000916000915b818310615d6e5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615da187856158b2565b511614615db7575b601001936001019190615d5c565b849350615da956fea164736f6c6343000817000a"; From ee873754a5fb92b367415a375ffaf78e5436f690 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 29 Jan 2024 23:14:52 +0200 Subject: [PATCH 041/132] Merge headers (#803) * style: merge storage and constants to state headers * style: declare first the immutable variables --- src/SablierV2Comptroller.sol | 2 +- src/SablierV2LockupDynamic.sol | 6 +----- src/SablierV2LockupLinear.sol | 2 +- src/abstracts/Adminable.sol | 2 +- src/abstracts/SablierV2Base.sol | 6 +----- src/abstracts/SablierV2Lockup.sol | 2 +- test/fork/Fork.t.sol | 7 +------ test/invariant/handlers/BaseHandler.sol | 6 +----- test/utils/Defaults.sol | 6 +----- 9 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/SablierV2Comptroller.sol b/src/SablierV2Comptroller.sol index 7be16b172..a1ba22632 100644 --- a/src/SablierV2Comptroller.sol +++ b/src/SablierV2Comptroller.sol @@ -33,7 +33,7 @@ contract SablierV2Comptroller is Adminable // 1 inherited component { /*////////////////////////////////////////////////////////////////////////// - PUBLIC STORAGE + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2Comptroller diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index e44d6113b..710ab5caa 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -48,16 +48,12 @@ contract SablierV2LockupDynamic is using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// - PUBLIC CONSTANTS + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2LockupDynamic uint256 public immutable override MAX_SEGMENT_COUNT; - /*////////////////////////////////////////////////////////////////////////// - PRIVATE STORAGE - //////////////////////////////////////////////////////////////////////////*/ - /// @dev Sablier V2 Lockup Dynamic streams mapped by unsigned integer ids. mapping(uint256 id => LockupDynamic.Stream stream) private _streams; diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index a1eb4f98f..d359ba790 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -43,7 +43,7 @@ contract SablierV2LockupLinear is using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// - PRIVATE STORAGE + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @dev Sablier V2 Lockup Linear streams mapped by unsigned integers. diff --git a/src/abstracts/Adminable.sol b/src/abstracts/Adminable.sol index 26171c59c..aac440d29 100644 --- a/src/abstracts/Adminable.sol +++ b/src/abstracts/Adminable.sol @@ -8,7 +8,7 @@ import { Errors } from "../libraries/Errors.sol"; /// @notice See the documentation in {IAdminable}. abstract contract Adminable is IAdminable { /*////////////////////////////////////////////////////////////////////////// - STORAGE + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc IAdminable diff --git a/src/abstracts/SablierV2Base.sol b/src/abstracts/SablierV2Base.sol index a93ca4277..2f4ba1904 100644 --- a/src/abstracts/SablierV2Base.sol +++ b/src/abstracts/SablierV2Base.sol @@ -22,16 +22,12 @@ abstract contract SablierV2Base is using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// - PUBLIC CONSTANTS + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2Base UD60x18 public constant override MAX_FEE = UD60x18.wrap(0.1e18); - /*////////////////////////////////////////////////////////////////////////// - PUBLIC STORAGE - //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Base ISablierV2Comptroller public override comptroller; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index d75a1f87d..2f6a30ea8 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -23,7 +23,7 @@ abstract contract SablierV2Lockup is ERC721 // 6 inherited components { /*////////////////////////////////////////////////////////////////////////// - USER-FACING STORAGE + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2Lockup diff --git a/test/fork/Fork.t.sol b/test/fork/Fork.t.sol index 32cd0ec83..831f93095 100644 --- a/test/fork/Fork.t.sol +++ b/test/fork/Fork.t.sol @@ -9,16 +9,11 @@ import { Base_Test } from "../Base.t.sol"; /// @notice Common logic needed by all fork tests. abstract contract Fork_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// - CONSTANTS + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ IERC20 internal immutable ASSET; address internal immutable HOLDER; - - /*////////////////////////////////////////////////////////////////////////// - VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - uint256 internal initialHolderBalance; /*////////////////////////////////////////////////////////////////////////// diff --git a/test/invariant/handlers/BaseHandler.sol b/test/invariant/handlers/BaseHandler.sol index 7719b88e4..9e204065c 100644 --- a/test/invariant/handlers/BaseHandler.sol +++ b/test/invariant/handlers/BaseHandler.sol @@ -12,7 +12,7 @@ import { TimestampStore } from "../stores/TimestampStore.sol"; /// @notice Base contract with common logic needed by all handler contracts. abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /*////////////////////////////////////////////////////////////////////////// - CONSTANTS + STATE-VARIABLES //////////////////////////////////////////////////////////////////////////*/ /// @dev Maximum number of streams that can be created during an invariant campaign. @@ -21,10 +21,6 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev The virtual address of the Foundry VM. address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - /*////////////////////////////////////////////////////////////////////////// - VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - /// @dev Maps function names to the number of times they have been called. mapping(string func => uint256 calls) public calls; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 36bbe5faf..c190854dc 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -13,7 +13,7 @@ import { Users } from "./Types.sol"; /// @notice Contract with default values used throughout the tests. contract Defaults is Constants { /*////////////////////////////////////////////////////////////////////////// - CONSTANTS + STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ UD60x18 public constant BROKER_FEE = UD60x18.wrap(0.003e18); // 0.3% @@ -35,10 +35,6 @@ contract Defaults is Constants { uint128 public constant WITHDRAW_AMOUNT = 2600e18; uint40 public immutable WARP_26_PERCENT; // 26% of the way through the stream - /*////////////////////////////////////////////////////////////////////////// - VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - IERC20 private asset; Users private users; From 6b80f71d71ccff230dd234d3188f022e2a3a2eb4 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 1 Feb 2024 22:32:06 +0530 Subject: [PATCH 042/132] refactor: fix title in ISablierV2Comptroller --- src/interfaces/ISablierV2Comptroller.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/ISablierV2Comptroller.sol b/src/interfaces/ISablierV2Comptroller.sol index ca5a718af..34bb413e0 100644 --- a/src/interfaces/ISablierV2Comptroller.sol +++ b/src/interfaces/ISablierV2Comptroller.sol @@ -6,7 +6,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { IAdminable } from "./IAdminable.sol"; -/// @title ISablierV2Controller +/// @title ISablierV2Comptroller /// @notice This contract is in charge of the Sablier V2 protocol configuration, handling such values as the /// protocol fees. interface ISablierV2Comptroller is IAdminable { From 110211f4fb8706aac6254b82b57cb4aea92a4624 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:00:53 +0200 Subject: [PATCH 043/132] Upgrade to OpenZeppelin V5 (#806) * build: update openzeppelin to 5.0.0 refactor: remove _after and _before hooks and implement _update function refactor: use newly added _requireOwned function refactor: use the new named parameter in ERC20 functions test: add mocks for ERC20 and ERC721 test: use openeppelin's custom errors in cheatcode chore: provide a more precise explanation for _update chore: define "_update" alphabetically docs: document "_update" function test: check IERC20Errors custom error revert * perf: optimize getRecipient function docs: use known terminology in _update natspec --- bun.lockb | Bin 43200 -> 43200 bytes package.json | 2 +- script/Init.s.sol | 8 +- src/abstracts/SablierV2Lockup.sol | 71 ++++++++---------- test/Base.t.sol | 38 +++++----- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 10 ++- .../lockup-dynamic/token-uri/tokenURI.t.sol | 3 +- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 13 ++-- .../lockup-linear/token-uri/tokenURI.t.sol | 3 +- .../concrete/lockup/burn/burn.t.sol | 10 ++- .../cancel-multiple/cancelMultiple.t.sol | 4 +- .../concrete/lockup/cancel/cancel.t.sol | 2 +- .../claimProtocolRevenues.t.sol | 2 +- .../lockup/get-recipient/getRecipient.t.sol | 6 +- .../withdrawMaxAndTransfer.t.sol | 2 +- .../lockup/withdraw-max/withdrawMax.t.sol | 4 +- .../withdraw-multiple/withdrawMultiple.t.sol | 6 +- .../concrete/lockup/withdraw/withdraw.t.sol | 2 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 4 +- .../safe-asset-symbol/safeAssetSymbol.t.sol | 9 +-- .../lockup-dynamic/createWithDurations.t.sol | 4 +- .../lockup-dynamic/createWithTimestamps.t.sol | 6 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 2 +- .../lockup-linear/createWithDurations.t.sol | 4 +- .../lockup-linear/createWithTimestamps.t.sol | 6 +- test/integration/fuzz/lockup/cancel.t.sol | 2 +- .../fuzz/lockup/cancelMultiple.t.sol | 4 +- test/integration/fuzz/lockup/withdraw.t.sol | 4 +- .../integration/fuzz/lockup/withdrawMax.t.sol | 4 +- .../fuzz/lockup/withdrawMaxAndTransfer.t.sol | 2 +- .../fuzz/lockup/withdrawMultiple.t.sol | 4 +- .../invariant/handlers/ComptrollerHandler.sol | 2 +- .../handlers/LockupDynamicCreateHandler.sol | 4 +- .../handlers/LockupLinearCreateHandler.sol | 4 +- test/mocks/erc20/ERC20Mock.sol | 8 ++ test/mocks/erc721/ERC721Mock.sol | 8 ++ 38 files changed, 147 insertions(+), 128 deletions(-) create mode 100644 test/mocks/erc20/ERC20Mock.sol create mode 100644 test/mocks/erc721/ERC721Mock.sol diff --git a/bun.lockb b/bun.lockb index 11a133d47dd94cfb065836d9c538241f1304cae3..d743b39cfd31130c1ae2f424cb898572ed6c4d90 100755 GIT binary patch delta 148 zcmV;F0Biri(E`BH0+22st#nZD1be)cmX60ZU*nl>rLHb@e!Nx?=xQ2<@gUqGu}%UA z0R@v$3OBQe2t6b~ZvCuvE{iIqRWPzS`#PsKvsC;bKI=Y$n*mpw^D~&^!9^pvt>Fnb zy!08o@3T+azw;Sob7Yq0>BBAW+vc;gvjr{7Oa(PAFfK5&)p;Tg1vM@(E-v()OJV-#1S>XWo3P z1_lPs$%35Pn;SS>RUBr#-}GYIsyNemM)C<$TZ_ZqvnPC9GKWDuS|`{|a9)w~>fNdr z3~oLx%-itCrnc_VJw;9{^Jku7Pt*JvtEV`zuG`G2d)kN9M9)&sX!F%dB|a$gPx}!C E04EVXm;e9( diff --git a/package.json b/package.json index ffffc4e16..758035e0c 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "url": "https://github.com/sablier-labs/v2-core/issues" }, "dependencies": { - "@openzeppelin/contracts": "4.9.2", + "@openzeppelin/contracts": "5.0.0", "@prb/math": "4.0.2" }, "devDependencies": { diff --git a/script/Init.s.sol b/script/Init.s.sol index cf71876a2..9d917df43 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -14,7 +14,7 @@ import { Broker, LockupDynamic, LockupLinear } from "../src/types/DataTypes.sol" import { BaseScript } from "./Base.s.sol"; interface IERC20Mint { - function mint(address beneficiary, uint256 amount) external; + function mint(address beneficiary, uint256 value) external; } /// @notice Initializes the protocol by setting up the comptroller and creating some streams. @@ -35,11 +35,11 @@ contract Init is BaseScript { //////////////////////////////////////////////////////////////////////////*/ // Mint enough assets to the sender. - IERC20Mint(address(asset)).mint({ beneficiary: sender, amount: 131_601.1e18 + 10_000e18 }); + IERC20Mint(address(asset)).mint({ beneficiary: sender, value: 131_601.1e18 + 10_000e18 }); // Approve the Sablier contracts to transfer the ERC-20 assets from the sender. - asset.approve({ spender: address(lockupLinear), amount: type(uint256).max }); - asset.approve({ spender: address(lockupDynamic), amount: type(uint256).max }); + asset.approve({ spender: address(lockupLinear), value: type(uint256).max }); + asset.approve({ spender: address(lockupDynamic), value: type(uint256).max }); // Create 7 Lockup Linear streams with various amounts and durations. // diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 2f6a30ea8..93301d4c0 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -73,11 +73,8 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function getRecipient(uint256 streamId) external view override returns (address recipient) { - // Checks: the stream NFT exists. - _requireMinted({ tokenId: streamId }); - - // The NFT owner is the stream's recipient. - recipient = _ownerOf(streamId); + // Checks: the stream NFT exists, and return the owner, which is the stream's recipient. + recipient = _requireOwned({ tokenId: streamId }); } /// @inheritdoc ISablierV2Lockup @@ -104,7 +101,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ERC721 function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri) { // Checks: the stream NFT exists. - _requireMinted({ tokenId: streamId }); + _requireOwned({ tokenId: streamId }); // Generate the URI describing the stream NFT. uri = nftDescriptor.tokenURI({ sablier: this, streamId: streamId }); @@ -355,39 +352,6 @@ 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) { @@ -403,6 +367,35 @@ abstract contract SablierV2Lockup is /// @dev Retrieves the stream's status without performing a null check. function _statusOf(uint256 streamId) internal view virtual returns (Lockup.Status); + /// @notice Overrides the internal ERC-721 `_update` function to check that the stream is transferable and emit + /// an ERC-4906 event. + /// @dev There are two cases when the transferable flag is ignored: + /// - If `from` is 0, then the update is a mint and is allowed. + /// - If `to` is 0, then the update is a burn and is also allowed. + /// @param to The address of the new recipient of the stream. + /// @param streamId Id of the stream to update. + /// @param auth Optional parameter. If the value is non 0, the upstream implementation of this function will check + /// that `auth` is either the recipient of the stream, or an approved third party. + /// @return The original recipient of the `streamId` before the update. + function _update( + address to, + uint256 streamId, + address auth + ) + internal + override + updateMetadata(streamId) + returns (address) + { + address from = _ownerOf(streamId); + + if (!isTransferable(streamId) && from != address(0) && to != address(0)) { + revert Errors.SablierV2Lockup_NotTransferable(streamId); + } + + return super._update(to, streamId, auth); + } + /// @dev See the documentation for the user-facing functions that call this internal function. function _withdrawableAmountOf(uint256 streamId) internal view virtual returns (uint128); diff --git a/test/Base.t.sol b/test/Base.t.sol index 84910fd2f..5ebd294c2 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; @@ -13,6 +12,7 @@ import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; import { Noop } from "./mocks/Noop.sol"; import { GoodRecipient } from "./mocks/hooks/GoodRecipient.sol"; @@ -39,7 +39,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi //////////////////////////////////////////////////////////////////////////*/ ISablierV2Comptroller internal comptroller; - ERC20 internal dai; + ERC20Mock internal dai; Defaults internal defaults; GoodRecipient internal goodRecipient; GoodSender internal goodSender; @@ -55,7 +55,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi function setUp() public virtual { // Deploy the base test contracts. - dai = new ERC20("Dai Stablecoin", "DAI"); + dai = new ERC20Mock("Dai Stablecoin", "DAI"); goodRecipient = new GoodRecipient(); goodSender = new GoodSender(); noop = new Noop(); @@ -96,26 +96,26 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi /// @dev Approves all V2 Core contracts to spend assets from the Sender, Recipient, Alice and Eve. function approveProtocol() internal { changePrank({ msgSender: users.sender }); - dai.approve({ spender: address(lockupLinear), amount: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); + dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); changePrank({ msgSender: users.recipient }); - dai.approve({ spender: address(lockupLinear), amount: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); + dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); changePrank({ msgSender: users.alice }); - dai.approve({ spender: address(lockupLinear), amount: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); + dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); changePrank({ msgSender: users.eve }); - dai.approve({ spender: address(lockupLinear), amount: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); + dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); @@ -160,22 +160,22 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi //////////////////////////////////////////////////////////////////////////*/ /// @dev Expects a call to {IERC20.transfer}. - function expectCallToTransfer(address to, uint256 amount) internal { - vm.expectCall({ callee: address(dai), data: abi.encodeCall(IERC20.transfer, (to, amount)) }); + function expectCallToTransfer(address to, uint256 value) internal { + vm.expectCall({ callee: address(dai), data: abi.encodeCall(IERC20.transfer, (to, value)) }); } /// @dev Expects a call to {IERC20.transfer}. - function expectCallToTransfer(IERC20 asset, address to, uint256 amount) internal { - vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transfer, (to, amount)) }); + function expectCallToTransfer(IERC20 asset, address to, uint256 value) internal { + vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transfer, (to, value)) }); } /// @dev Expects a call to {IERC20.transferFrom}. - function expectCallToTransferFrom(address from, address to, uint256 amount) internal { - vm.expectCall({ callee: address(dai), data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); + function expectCallToTransferFrom(address from, address to, uint256 value) internal { + vm.expectCall({ callee: address(dai), data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) }); } /// @dev Expects a call to {IERC20.transferFrom}. - function expectCallToTransferFrom(IERC20 asset, address from, address to, uint256 amount) internal { - vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); + function expectCallToTransferFrom(IERC20 asset, address from, address to, uint256 value) internal { + vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) }); } } diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index bf8b3823c..41d2449b6 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -143,11 +143,11 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), - amount: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() }); // Expect the broker fee to be paid to the broker. - expectCallToTransferFrom({ from: funder, to: users.broker, amount: defaults.BROKER_FEE_AMOUNT() }); + expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index f7842897b..75ad84408 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; @@ -33,8 +35,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is } function test_RevertWhen_RecipientZeroAddress() external whenNotDelegateCalled { - vm.expectRevert("ERC721: mint to the zero address"); address recipient = address(0); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); createDefaultStreamWithRecipient(recipient); } @@ -295,7 +297,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is changePrank({ msgSender: users.sender }); // Run the test. - vm.expectRevert("Address: call to non-contract"); + vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); createDefaultStreamWithAsset(IERC20(nonContract)); } @@ -348,7 +350,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: address(lockupDynamic), - amount: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() }); // Expect the broker fee to be paid to the broker. @@ -356,7 +358,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: users.broker, - amount: defaults.BROKER_FEE_AMOUNT() + value: defaults.BROKER_FEE_AMOUNT() }); // Expect the relevant events to be emitted. diff --git a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol index c096e584e..c01dcc249 100644 --- a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol @@ -2,6 +2,7 @@ // solhint-disable max-line-length,no-console,quotes pragma solidity >=0.8.22 <0.9.0; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { console2 } from "forge-std/src/console2.sol"; import { LibString } from "solady/src/utils/LibString.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; @@ -33,7 +34,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ function test_RevertGiven_NFTDoesNotExist() external { uint256 nullStreamId = 1729; - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); lockupDynamic.tokenURI({ tokenId: nullStreamId }); } diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 835b7af64..1268f5a57 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -104,11 +104,11 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is expectCallToTransferFrom({ from: funder, to: address(lockupLinear), - amount: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() }); // Expect the broker fee to be paid to the broker. - expectCallToTransferFrom({ from: funder, to: users.broker, amount: defaults.BROKER_FEE_AMOUNT() }); + expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockupLinear) }); diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 1cc002290..f4b4b656a 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; @@ -32,8 +34,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is } function test_RevertWhen_RecipientZeroAddress() external whenNotDelegateCalled { - vm.expectRevert("ERC721: mint to the zero address"); - createDefaultStreamWithRecipient({ recipient: address(0) }); + address recipient = address(0); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); + createDefaultStreamWithRecipient(recipient); } /// @dev It is not possible to obtain a zero deposit amount from a non-zero total amount, because the @@ -143,7 +146,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenBrokerFeeNotTooHigh { address nonContract = address(8128); - vm.expectRevert("Address: call to non-contract"); + vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); createDefaultStreamWithAsset(IERC20(nonContract)); } @@ -187,7 +190,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: address(lockupLinear), - amount: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() }); // Expect the broker fee to be paid to the broker. @@ -195,7 +198,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: users.broker, - amount: defaults.BROKER_FEE_AMOUNT() + value: defaults.BROKER_FEE_AMOUNT() }); // Expect the relevant events to be emitted. diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol index 3b1443033..ac8eafa30 100644 --- a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol @@ -2,6 +2,7 @@ // solhint-disable max-line-length,no-console,quotes pragma solidity >=0.8.22 <0.9.0; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { console2 } from "forge-std/src/console2.sol"; import { LibString } from "solady/src/utils/LibString.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; @@ -33,7 +34,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra function test_RevertGiven_NFTDoesNotExist() external { uint256 nullStreamId = 1729; - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); lockupLinear.tokenURI({ tokenId: nullStreamId }); } diff --git a/test/integration/concrete/lockup/burn/burn.t.sol b/test/integration/concrete/lockup/burn/burn.t.sol index 88d8d52a3..0e98fb24b 100644 --- a/test/integration/concrete/lockup/burn/burn.t.sol +++ b/test/integration/concrete/lockup/burn/burn.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; + import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Errors } from "src/libraries/Errors.sol"; @@ -122,7 +124,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int lockup.burn(streamId); // Run the test. - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, streamId)); lockup.burn(streamId); } @@ -142,7 +144,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: notTransferableStreamId }); lockup.burn(notTransferableStreamId); - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, notTransferableStreamId)); lockup.getRecipient(notTransferableStreamId); } @@ -173,7 +175,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int lockup.burn(streamId); // Assert that the NFT has been burned. - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, streamId)); lockup.getRecipient(streamId); } @@ -190,7 +192,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); lockup.burn(streamId); - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, streamId)); lockup.getRecipient(streamId); } } diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index 6f834ec03..dbb24c005 100644 --- a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -172,9 +172,9 @@ abstract contract CancelMultiple_Integration_Concrete_Test is // Expect the assets to be refunded to the stream's sender. uint128 senderAmount0 = lockup.refundableAmountOf(testStreamIds[0]); - expectCallToTransfer({ to: users.sender, amount: senderAmount0 }); + expectCallToTransfer({ to: users.sender, value: senderAmount0 }); uint128 senderAmount1 = lockup.refundableAmountOf(testStreamIds[1]); - expectCallToTransfer({ to: users.sender, amount: senderAmount1 }); + expectCallToTransfer({ to: users.sender, value: senderAmount1 }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/integration/concrete/lockup/cancel/cancel.t.sol index 38a43306b..f77ec8659 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/integration/concrete/lockup/cancel/cancel.t.sol @@ -242,7 +242,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I // Expect the assets to be refunded to the Sender. uint128 senderAmount = lockup.refundableAmountOf(streamId); - expectCallToTransfer({ to: users.sender, amount: senderAmount }); + expectCallToTransfer({ to: users.sender, value: senderAmount }); // Expect a call to the hook. uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); diff --git a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol index 4e469277a..5630dd404 100644 --- a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol +++ b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol @@ -43,7 +43,7 @@ abstract contract ClaimProtocolRevenues_Integration_Concrete_Test is function test_ClaimProtocolRevenues() external whenCallerAdmin givenProtocolRevenuesNotZero { // Expect the protocol revenues to be claimed. uint128 protocolRevenues = defaults.PROTOCOL_FEE_AMOUNT(); - expectCallToTransfer({ to: users.admin, amount: protocolRevenues }); + expectCallToTransfer({ to: users.admin, value: protocolRevenues }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(base) }); diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol index 603b3f5b3..af633fb63 100644 --- a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; + import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -13,7 +15,7 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); lockup.getRecipient(nullStreamId); } @@ -35,7 +37,7 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo lockup.burn(defaultStreamId); // Expect the relevant error when retrieving the recipient. - vm.expectRevert("ERC721: invalid token ID"); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, defaultStreamId)); lockup.getRecipient(defaultStreamId); } diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 6a1d30083..3e96b4ab7 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -96,7 +96,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index c1bb73538..2719b7eff 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -16,7 +16,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit vm.warp({ timestamp: defaults.END_TIME() + 1 seconds }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -58,7 +58,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index 915b4c709..dc9c75832 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -190,9 +190,9 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is changePrank({ msgSender: caller }); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient, amount: testAmounts[0] }); - expectCallToTransfer({ to: users.recipient, amount: testAmounts[1] }); - expectCallToTransfer({ to: users.recipient, amount: testAmounts[2] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[0] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[1] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[2] }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 8c488b240..9e4b9002e 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -619,7 +619,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); // Expect the assets to be transferred to the recipient contract. - expectCallToTransfer({ to: address(recipient), amount: withdrawAmount }); + expectCallToTransfer({ to: address(recipient), value: withdrawAmount }); // Expect a call to the hook if the recipient is a contract. if (recipient.code.length > 0) { diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 30f52ea55..2e22d6933 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import { ERC721Mock } from "../../../../mocks/erc721/ERC721Mock.sol"; import { Errors } from "src/libraries/Errors.sol"; @@ -9,7 +9,7 @@ import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol" contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { function test_RevertGiven_UnknownNFT() external { - ERC721 nft = new ERC721("Foo NFT", "FOO"); + ERC721Mock nft = new ERC721Mock("Foo NFT", "FOO"); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2NFTDescriptor_UnknownNFT.selector, nft, "FOO")); nftDescriptorMock.mapSymbol_(nft); } diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index ea4b48345..8d7d8e3eb 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - +import { ERC20Mock } from "../../../../mocks/erc20/ERC20Mock.sol"; import { ERC20Bytes32 } from "../../../../mocks/erc20/ERC20Bytes32.sol"; import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; @@ -36,9 +35,9 @@ contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_ } function test_SafeAssetSymbol_LongSymbol() external whenERC20Contract givenSymbolString { - ERC20 asset = new ERC20({ - name_: "Token", - symbol_: "This symbol is has more than 30 characters and it should be ignored" + ERC20Mock asset = new ERC20Mock({ + name: "Token", + symbol: "This symbol is has more than 30 characters and it should be ignored" }); string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset)); string memory expectedSymbol = "Long Symbol"; diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 4285a8034..7ceb58e9d 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -66,12 +66,12 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is expectCallToTransferFrom({ from: vars.funder, to: address(lockupDynamic), - amount: vars.createAmounts.deposit + vars.createAmounts.protocolFee + value: vars.createAmounts.deposit + vars.createAmounts.protocolFee }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { - expectCallToTransferFrom({ from: vars.funder, to: users.broker, amount: vars.createAmounts.brokerFee }); + expectCallToTransferFrom({ from: vars.funder, to: users.broker, value: vars.createAmounts.brokerFee }); } // Create the range struct. diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 16909789f..861f34eb9 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -252,18 +252,18 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: funder, give: vars.totalAmount }); // Approve {SablierV2LockupDynamic} to transfer the assets from the fuzzed funder. - dai.approve({ spender: address(lockupDynamic), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), - amount: vars.createAmounts.deposit + vars.createAmounts.protocolFee + value: vars.createAmounts.deposit + vars.createAmounts.protocolFee }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { - expectCallToTransferFrom({ from: funder, to: params.broker.account, amount: vars.createAmounts.brokerFee }); + expectCallToTransferFrom({ from: funder, to: params.broker.account, value: vars.createAmounts.brokerFee }); } // Expect the relevant event to be emitted. diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index 564039809..576b359dc 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -93,7 +93,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); // Expect the assets to be transferred to the fuzzed `to` address. - expectCallToTransfer({ to: params.to, amount: vars.withdrawAmount }); + expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index 1a0633906..d6194802d 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -94,11 +94,11 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is expectCallToTransferFrom({ from: funder, to: address(lockupLinear), - amount: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() }); // Expect the broker fee to be paid to the broker. - expectCallToTransferFrom({ from: funder, to: users.broker, amount: defaults.BROKER_FEE_AMOUNT() }); + expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); // Create the range struct by calculating the start time, cliff time and the end time. LockupLinear.Range memory range = LockupLinear.Range({ diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 1916ea86f..0e2e23baa 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -166,18 +166,18 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: funder, give: params.totalAmount }); // Approve {SablierV2LockupLinear} to transfer the assets from the fuzzed funder. - dai.approve({ spender: address(lockupLinear), amount: MAX_UINT256 }); + dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. expectCallToTransferFrom({ from: funder, to: address(lockupLinear), - amount: vars.createAmounts.deposit + vars.createAmounts.protocolFee + value: vars.createAmounts.deposit + vars.createAmounts.protocolFee }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { - expectCallToTransferFrom({ from: funder, to: params.broker.account, amount: vars.createAmounts.brokerFee }); + expectCallToTransferFrom({ from: funder, to: params.broker.account, value: vars.createAmounts.brokerFee }); } // Expect the relevant event to be emitted. diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/integration/fuzz/lockup/cancel.t.sol index b1b7f59e6..165c4c8cd 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/integration/fuzz/lockup/cancel.t.sol @@ -76,7 +76,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ // Expect the assets to be refunded to the Sender. uint128 senderAmount = lockup.refundableAmountOf(streamId); - expectCallToTransfer({ to: users.sender, amount: senderAmount }); + expectCallToTransfer({ to: users.sender, value: senderAmount }); // Expect the relevant events to be emitted. uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); diff --git a/test/integration/fuzz/lockup/cancelMultiple.t.sol b/test/integration/fuzz/lockup/cancelMultiple.t.sol index 42b61f0c8..6e372b1ae 100644 --- a/test/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/integration/fuzz/lockup/cancelMultiple.t.sol @@ -38,9 +38,9 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc // Expect the assets to be refunded to the Sender. uint128 senderAmount0 = lockup.refundableAmountOf(streamIds[0]); - expectCallToTransfer({ to: users.sender, amount: senderAmount0 }); + expectCallToTransfer({ to: users.sender, value: senderAmount0 }); uint128 senderAmount1 = lockup.refundableAmountOf(streamIds[1]); - expectCallToTransfer({ to: users.sender, amount: senderAmount1 }); + expectCallToTransfer({ to: users.sender, value: senderAmount1 }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/integration/fuzz/lockup/withdraw.t.sol index 4079206c5..8f591955e 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/integration/fuzz/lockup/withdraw.t.sol @@ -115,7 +115,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I withdrawAmount = boundUint128(withdrawAmount, 1, withdrawableAmount); // Expect the assets to be transferred to the fuzzed `to` address. - expectCallToTransfer({ to: to, amount: withdrawAmount }); + expectCallToTransfer({ to: to, value: withdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -177,7 +177,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I withdrawAmount = boundUint128(withdrawAmount, 1, withdrawableAmount); // Expect the assets to be transferred to the fuzzed `to` address. - expectCallToTransfer({ to: to, amount: withdrawAmount }); + expectCallToTransfer({ to: to, value: withdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/fuzz/lockup/withdrawMax.t.sol b/test/integration/fuzz/lockup/withdrawMax.t.sol index d4e4ba06e..a9d8d5add 100644 --- a/test/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/integration/fuzz/lockup/withdrawMax.t.sol @@ -18,7 +18,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra vm.warp({ timestamp: defaults.START_TIME() + timeJump }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -62,7 +62,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, amount: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol index cab8413e5..198fa4e2d 100644 --- a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol @@ -38,7 +38,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is if (withdrawAmount > 0) { // Expect the assets to be transferred to the fuzzed recipient. - expectCallToTransfer({ to: users.recipient, amount: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/integration/fuzz/lockup/withdrawMultiple.t.sol index 7cabecba9..71f0a5ac1 100644 --- a/test/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -52,8 +52,8 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is ongoingWithdrawAmount = boundUint128(ongoingWithdrawAmount, 1, ongoingWithdrawableAmount); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient, amount: ongoingWithdrawAmount }); - expectCallToTransfer({ to: users.recipient, amount: settledWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: ongoingWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: settledWithdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/invariant/handlers/ComptrollerHandler.sol b/test/invariant/handlers/ComptrollerHandler.sol index 71575e49a..061f8e5a7 100644 --- a/test/invariant/handlers/ComptrollerHandler.sol +++ b/test/invariant/handlers/ComptrollerHandler.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18, UNIT } from "@prb/math/src/UD60x18.sol"; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 41eb5d3cf..3c97d9cd8 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -83,7 +83,7 @@ contract LockupDynamicCreateHandler is BaseHandler { deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); // Approve {SablierV2LockupDynamic} to spend the assets. - asset.approve({ spender: address(lockupDynamic), amount: params.totalAmount }); + asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); // Create the stream. params.asset = asset; @@ -131,7 +131,7 @@ contract LockupDynamicCreateHandler is BaseHandler { deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); // Approve {SablierV2LockupDynamic} to spend the assets. - asset.approve({ spender: address(lockupDynamic), amount: params.totalAmount }); + asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); // Create the stream. params.asset = asset; diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index 1635c3f03..940b771ea 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -67,7 +67,7 @@ contract LockupLinearCreateHandler is BaseHandler { deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); // Approve {SablierV2LockupLinear} to spend the assets. - asset.approve({ spender: address(lockupLinear), amount: params.totalAmount }); + asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); // Create the stream. params.asset = asset; @@ -110,7 +110,7 @@ contract LockupLinearCreateHandler is BaseHandler { deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); // Approve {SablierV2LockupLinear} to spend the assets. - asset.approve({ spender: address(lockupLinear), amount: params.totalAmount }); + asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); // Create the stream. params.asset = asset; diff --git a/test/mocks/erc20/ERC20Mock.sol b/test/mocks/erc20/ERC20Mock.sol new file mode 100644 index 000000000..8cf2389dd --- /dev/null +++ b/test/mocks/erc20/ERC20Mock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) { } +} diff --git a/test/mocks/erc721/ERC721Mock.sol b/test/mocks/erc721/ERC721Mock.sol new file mode 100644 index 000000000..004190ba6 --- /dev/null +++ b/test/mocks/erc721/ERC721Mock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract ERC721Mock is ERC721 { + constructor(string memory name, string memory symbol) ERC721(name, symbol) { } +} From 37b86d88e6f39c0e49d7faa21e88b7c20b9e888a Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Sat, 10 Feb 2024 13:58:29 +0200 Subject: [PATCH 044/132] refactor: change information when the nft is non-transferable --- src/SablierV2NFTDescriptor.sol | 18 ++++++-- test/mocks/NFTDescriptorMock.sol | 7 +-- .../nft-descriptor/generateDescription.t.sol | 46 ++++++++++++++++--- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 5601cc2e1..0d3486ed2 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -90,9 +90,10 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { generateDescription({ streamingModel: vars.streamingModel, assetSymbol: vars.assetSymbol, - streamId: streamId.toString(), sablierAddress: vars.sablierAddress, - assetAddress: vars.asset.toHexString() + assetAddress: vars.asset.toHexString(), + streamId: streamId.toString(), + isTransferable: vars.sablier.isTransferable(streamId) }), '","external_url":"https://sablier.com","name":"', generateName({ streamingModel: vars.streamingModel, streamId: streamId.toString() }), @@ -250,14 +251,21 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { function generateDescription( string memory streamingModel, string memory assetSymbol, - string memory streamId, string memory sablierAddress, - string memory assetAddress + string memory assetAddress, + string memory streamId, + bool isTransferable ) internal pure returns (string memory) { + // Depending on the transferability of the NFT, declare the relevant information. + string memory info = isTransferable + ? + unicode"⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient." + : unicode"❕INFO: This NFT is non-transferable. It cannot be sold or transferred to another account."; + return string.concat( "This NFT represents a payment stream in a Sablier V2 ", streamingModel, @@ -274,7 +282,7 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { " Address: ", assetAddress, "\\n\\n", - unicode"⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient." + info ); } diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index 6d93fb7d8..47bcf5aee 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -54,15 +54,16 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { function generateDescription_( string memory streamingModel, string memory assetSymbol, - string memory streamId, string memory sablierAddress, - string memory assetAddress + string memory assetAddress, + string memory streamId, + bool isTransferable ) external pure returns (string memory) { - return generateDescription(streamingModel, assetSymbol, streamId, sablierAddress, assetAddress); + return generateDescription(streamingModel, assetSymbol, sablierAddress, assetAddress, streamId, isTransferable); } function generateName_( diff --git a/test/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/unit/concrete/nft-descriptor/generateDescription.t.sol index 8a295e59e..58664a40f 100644 --- a/test/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/test/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -5,11 +5,13 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - string internal constant DISCLAIMER = + string internal constant INFO_NON_TRANSFERABLE = + unicode"❕INFO: This NFT is non-transferable. It cannot be sold or transferred to another account."; + string internal constant INFO_TRANSFERABLE = unicode"⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient."; function test_GenerateDescription_Empty() external { - string memory actualDescription = nftDescriptorMock.generateDescription_("", "", "", "", ""); + string memory actualDescription = nftDescriptorMock.generateDescription_("", "", "", "", "", true); string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier V2 ", " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", @@ -20,18 +22,50 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T "\\n- ", " Address: ", "\\n\\n", - DISCLAIMER + INFO_TRANSFERABLE ); assertEq(actualDescription, expectedDescription, "metadata description"); } - function test_GenerateDescription() external { + function test_GenerateDescription_NonTransferable() external { string memory actualDescription = nftDescriptorMock.generateDescription_( "Lockup Linear", dai.symbol(), + "0x78B190C1E493752f85E02b00a0C98851A5638A30", + "0xFEbD67A34821d1607a57DD31aae5f246D7dE2ca2", + "42", + false + ); + string memory expectedDescription = string.concat( + "This NFT represents a payment stream in a Sablier V2 ", + "Lockup Linear", + " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", + dai.symbol(), + ".\\n\\n", + "- Stream ID: ", "42", + "\\n- ", + "Lockup Linear", + " Address: ", "0x78B190C1E493752f85E02b00a0C98851A5638A30", - "0xFEbD67A34821d1607a57DD31aae5f246D7dE2ca2" + "\\n- ", + "DAI", + " Address: ", + "0xFEbD67A34821d1607a57DD31aae5f246D7dE2ca2", + "\\n\\n", + INFO_NON_TRANSFERABLE + ); + assertEq(actualDescription, expectedDescription, "metadata description"); + } + + function test_GenerateDescription() external { + string memory actualDescription = nftDescriptorMock.generateDescription_( + "Lockup Linear", + dai.symbol(), + "0x78B190C1E493752f85E02b00a0C98851A5638A30", + "0xFEbD67A34821d1607a57DD31aae5f246D7dE2ca2", + "42", + true ); string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier V2 ", @@ -50,7 +84,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T " Address: ", "0xFEbD67A34821d1607a57DD31aae5f246D7dE2ca2", "\\n\\n", - DISCLAIMER + INFO_TRANSFERABLE ); assertEq(actualDescription, expectedDescription, "metadata description"); } From 9fc27477c8fbd4b6fd0fff2c1b7a892bc615106a Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 12 Feb 2024 16:00:27 +0200 Subject: [PATCH 045/132] test: pragma solidity >=0.8.22 in base script test --- test/utils/BaseScript.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index bf9533720..e27ad1b68 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.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.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { PRBTest } from "@prb/test/src/PRBTest.sol"; From e4583dce53d21220d365f1049f97908fa3e7f7a3 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:04:03 +0200 Subject: [PATCH 046/132] Move all duplicated logic in the abstract contract `SablierV2Lockup` (#813) * build: update openzeppelin to 5.0.0 refactor: remove _after and _before hooks and implement _update function refactor: use newly added _requireOwned function refactor: use the new named parameter in ERC20 functions test: add mocks for ERC20 and ERC721 test: use openeppelin's custom errors in cheatcode chore: provide a more precise explanation for _update chore: define "_update" alphabetically docs: document "_update" function test: check IERC20Errors custom error revert * feat: add Lockup.Stream struct feat: add mapping for cliffs in linear feat: add mapping for segments in dynamic refactor: move all common functions in SablierV2Lockup * perf: use the storages instead of the getters * feat: check if the start time is zero feat: check if the start time is greater than end time test: update tests accordingly * docs: re-add natspec for _calculateStreamedAmountForMultipleSegments * refactor: make start time strictly less than cliff time * chore: update branch from staging * docs: use plural * refactor: order constant functions alphabetically refactor: make constant functions external * refactor: make cliff time strictly greater than start time * docs: correct natspec chore: use "override" specifier on nftDescriptor * test: update comment for using unchecked to allow overflow * docs: improve natspec chore: order functions alphabetically in SablierV2Lockup * refactor: rename Stream structs within LockupLinear and LockupDynamic namespaces --------- Co-authored-by: smol-ninja --- src/SablierV2LockupDynamic.sol | 336 ++---------------- src/SablierV2LockupLinear.sol | 328 ++--------------- src/abstracts/SablierV2Lockup.sol | 290 +++++++++++++-- src/interfaces/ISablierV2LockupDynamic.sol | 4 +- src/interfaces/ISablierV2LockupLinear.sol | 14 +- src/libraries/Errors.sol | 8 +- src/libraries/Helpers.sol | 16 +- src/types/DataTypes.sol | 78 ++-- test/fork/LockupDynamic.t.sol | 2 +- test/fork/LockupLinear.t.sol | 4 +- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 4 +- .../lockup-dynamic/get-stream/getStream.t.sol | 8 +- .../createWithDurations.t.sol | 32 +- .../createWithDurations.tree | 3 - .../createWithTimestamps.t.sol | 75 +++- .../createWithTimestamps.tree | 67 ++-- .../lockup-linear/get-stream/getStream.t.sol | 8 +- .../lockup-dynamic/createWithDurations.t.sol | 2 +- .../lockup-dynamic/createWithTimestamps.t.sol | 2 +- .../lockup-linear/createWithDurations.t.sol | 39 +- .../lockup-linear/createWithTimestamps.t.sol | 10 +- test/invariant/LockupDynamic.t.sol | 4 +- test/invariant/LockupLinear.t.sol | 20 +- .../handlers/LockupLinearCreateHandler.sol | 4 +- test/utils/Assertions.sol | 4 +- test/utils/Defaults.sol | 8 +- 27 files changed, 571 insertions(+), 803 deletions(-) diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 710ab5caa..197c3c78d 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -11,11 +11,8 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; -import { ISablierV2Lockup } from "./interfaces/ISablierV2Lockup.sol"; import { ISablierV2LockupDynamic } from "./interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2Recipient } from "./interfaces/hooks/ISablierV2Recipient.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; -import { Errors } from "./libraries/Errors.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupDynamic } from "./types/DataTypes.sol"; @@ -54,8 +51,8 @@ contract SablierV2LockupDynamic is /// @inheritdoc ISablierV2LockupDynamic uint256 public immutable override MAX_SEGMENT_COUNT; - /// @dev Sablier V2 Lockup Dynamic streams mapped by unsigned integer ids. - mapping(uint256 id => LockupDynamic.Stream stream) private _streams; + /// @dev Stream segments mapped by stream ids. + mapping(uint256 id => LockupDynamic.Segment[] segments) internal _segments; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -83,27 +80,6 @@ contract SablierV2LockupDynamic is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Lockup - function getAsset(uint256 streamId) external view override notNull(streamId) returns (IERC20 asset) { - asset = _streams[streamId].asset; - } - - /// @inheritdoc ISablierV2Lockup - function getDepositedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 depositedAmount) - { - depositedAmount = _streams[streamId].amounts.deposited; - } - - /// @inheritdoc ISablierV2Lockup - function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime) { - endTime = _streams[streamId].endTime; - } - /// @inheritdoc ISablierV2LockupDynamic function getRange(uint256 streamId) external @@ -115,17 +91,6 @@ contract SablierV2LockupDynamic is range = LockupDynamic.Range({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); } - /// @inheritdoc ISablierV2Lockup - function getRefundedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundedAmount) - { - refundedAmount = _streams[streamId].amounts.refunded; - } - /// @inheritdoc ISablierV2LockupDynamic function getSegments(uint256 streamId) external @@ -134,23 +99,7 @@ contract SablierV2LockupDynamic is notNull(streamId) returns (LockupDynamic.Segment[] memory segments) { - segments = _streams[streamId].segments; - } - - /// @inheritdoc ISablierV2Lockup - function getSender(uint256 streamId) - public - view - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (address sender) - { - sender = _streams[streamId].sender; - } - - /// @inheritdoc ISablierV2Lockup - function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime) { - startTime = _streams[streamId].startTime; + segments = _segments[streamId]; } /// @inheritdoc ISablierV2LockupDynamic @@ -159,103 +108,38 @@ contract SablierV2LockupDynamic is view override notNull(streamId) - returns (LockupDynamic.Stream memory stream) + returns (LockupDynamic.StreamLD memory stream) { - stream = _streams[streamId]; + Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. if (_statusOf(streamId) == Lockup.Status.SETTLED) { - stream.isCancelable = false; + lockupStream.isCancelable = false; } - } - /// @inheritdoc ISablierV2Lockup - function getWithdrawnAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 withdrawnAmount) - { - withdrawnAmount = _streams[streamId].amounts.withdrawn; - } - - /// @inheritdoc ISablierV2Lockup - function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result) { - if (_statusOf(streamId) != Lockup.Status.SETTLED) { - result = _streams[streamId].isCancelable; - } - } - - /// @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 - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (bool result) - { - result = _streams[streamId].isDepleted; - } - - /// @inheritdoc ISablierV2Lockup - function isStream(uint256 streamId) public view override(ISablierV2Lockup, SablierV2Lockup) returns (bool result) { - result = _streams[streamId].isStream; - } - - /// @inheritdoc ISablierV2Lockup - function refundableAmountOf(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundableAmount) - { - // These checks are needed because {_calculateStreamedAmount} does not look up the stream's status. Note that - // checking for `isCancelable` also checks if the stream `wasCanceled` thanks to the protocol invariant that - // canceled streams are not cancelable anymore. - if (_streams[streamId].isCancelable && !_streams[streamId].isDepleted) { - refundableAmount = _streams[streamId].amounts.deposited - _calculateStreamedAmount(streamId); - } - // Otherwise, the result is implicitly zero. - } - - /// @inheritdoc ISablierV2Lockup - function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status) { - status = _statusOf(streamId); + stream = LockupDynamic.StreamLD({ + amounts: lockupStream.amounts, + asset: lockupStream.asset, + endTime: lockupStream.endTime, + isCancelable: lockupStream.isCancelable, + isTransferable: lockupStream.isTransferable, + isDepleted: lockupStream.isDepleted, + isStream: lockupStream.isStream, + sender: lockupStream.sender, + segments: _segments[streamId], + startTime: lockupStream.startTime, + wasCanceled: lockupStream.wasCanceled + }); } /// @inheritdoc ISablierV2LockupDynamic function streamedAmountOf(uint256 streamId) public view - override(ISablierV2Lockup, ISablierV2LockupDynamic) - notNull(streamId) - returns (uint128 streamedAmount) - { - streamedAmount = _streamedAmountOf(streamId); - } - - /// @inheritdoc ISablierV2Lockup - function wasCanceled(uint256 streamId) - public - view - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (bool result) + override(SablierV2Lockup, ISablierV2LockupDynamic) + returns (uint128) { - result = _streams[streamId].wasCanceled; + return super.streamedAmountOf(streamId); } /*////////////////////////////////////////////////////////////////////////// @@ -303,8 +187,8 @@ contract SablierV2LockupDynamic is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Calculates the streamed amount without looking up the stream's status. - function _calculateStreamedAmount(uint256 streamId) internal view returns (uint128) { + /// @inheritdoc SablierV2Lockup + function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the start time is in the future, return zero. uint40 currentTime = uint40(block.timestamp); if (_streams[streamId].startTime >= currentTime) { @@ -317,7 +201,7 @@ contract SablierV2LockupDynamic is return _streams[streamId].amounts.deposited; } - if (_streams[streamId].segments.length > 1) { + if (_segments[streamId].length > 1) { // If there is more than one segment, it may be necessary to iterate over all of them. return _calculateStreamedAmountForMultipleSegments(streamId); } else { @@ -337,28 +221,29 @@ contract SablierV2LockupDynamic is function _calculateStreamedAmountForMultipleSegments(uint256 streamId) internal view returns (uint128) { unchecked { uint40 currentTime = uint40(block.timestamp); - LockupDynamic.Stream memory stream = _streams[streamId]; + Lockup.Stream memory stream = _streams[streamId]; + LockupDynamic.Segment[] memory segments = _segments[streamId]; // Sum the amounts in all segments that precede the current time. uint128 previousSegmentAmounts; - uint40 currentSegmentTimestamp = stream.segments[0].timestamp; + uint40 currentSegmentTimestamp = segments[0].timestamp; uint256 index = 0; while (currentSegmentTimestamp < currentTime) { - previousSegmentAmounts += stream.segments[index].amount; + previousSegmentAmounts += segments[index].amount; index += 1; - currentSegmentTimestamp = stream.segments[index].timestamp; + currentSegmentTimestamp = segments[index].timestamp; } // After exiting the loop, the current segment is at `index`. - SD59x18 currentSegmentAmount = stream.segments[index].amount.intoSD59x18(); - SD59x18 currentSegmentExponent = stream.segments[index].exponent.intoSD59x18(); - currentSegmentTimestamp = stream.segments[index].timestamp; + SD59x18 currentSegmentAmount = segments[index].amount.intoSD59x18(); + SD59x18 currentSegmentExponent = segments[index].exponent.intoSD59x18(); + currentSegmentTimestamp = segments[index].timestamp; uint40 previousTimestamp; if (index > 0) { // When the current segment's index is greater than or equal to 1, it implies that the segment is not // the first. In this case, use the previous segment's timestamp. - previousTimestamp = stream.segments[index - 1].timestamp; + previousTimestamp = segments[index - 1].timestamp; } else { // Otherwise, the current segment is the first, so use the start time as the previous timestamp. previousTimestamp = stream.startTime; @@ -403,7 +288,7 @@ contract SablierV2LockupDynamic is SD59x18 elapsedTimePercentage = elapsedTime.div(totalTime); // Cast the stream parameters to SD59x18. - SD59x18 exponent = _streams[streamId].segments[0].exponent.intoSD59x18(); + SD59x18 exponent = _segments[streamId][0].exponent.intoSD59x18(); SD59x18 depositedAmount = _streams[streamId].amounts.deposited.intoSD59x18(); // Calculate the streamed amount using the special formula. @@ -422,116 +307,10 @@ contract SablierV2LockupDynamic is } } - /// @inheritdoc SablierV2Lockup - function _isCallerStreamSender(uint256 streamId) internal view override returns (bool) { - return msg.sender == _streams[streamId].sender; - } - - /// @inheritdoc SablierV2Lockup - function _statusOf(uint256 streamId) internal view override returns (Lockup.Status) { - if (_streams[streamId].isDepleted) { - return Lockup.Status.DEPLETED; - } else if (_streams[streamId].wasCanceled) { - return Lockup.Status.CANCELED; - } - - if (block.timestamp < _streams[streamId].startTime) { - return Lockup.Status.PENDING; - } - - if (_calculateStreamedAmount(streamId) < _streams[streamId].amounts.deposited) { - return Lockup.Status.STREAMING; - } else { - return Lockup.Status.SETTLED; - } - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _streamedAmountOf(uint256 streamId) internal view returns (uint128) { - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - if (_streams[streamId].isDepleted) { - return amounts.withdrawn; - } else if (_streams[streamId].wasCanceled) { - return amounts.deposited - amounts.refunded; - } - - return _calculateStreamedAmount(streamId); - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdrawableAmountOf(uint256 streamId) internal view override returns (uint128) { - return _streamedAmountOf(streamId) - _streams[streamId].amounts.withdrawn; - } - /*////////////////////////////////////////////////////////////////////////// INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev See the documentation for the user-facing functions that call this internal function. - function _cancel(uint256 streamId) internal override { - // Calculate the streamed amount. - uint128 streamedAmount = _calculateStreamedAmount(streamId); - - // Retrieve the amounts from storage. - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - // Checks: the stream is not settled. - if (streamedAmount >= amounts.deposited) { - revert Errors.SablierV2Lockup_StreamSettled(streamId); - } - - // Checks: the stream is cancelable. - if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); - } - - // Calculate the sender's and the recipient's amount. - uint128 senderAmount = amounts.deposited - streamedAmount; - uint128 recipientAmount = streamedAmount - amounts.withdrawn; - - // Effects: mark the stream as canceled. - _streams[streamId].wasCanceled = true; - - // Effects: make the stream not cancelable anymore, because a stream can only be canceled once. - _streams[streamId].isCancelable = false; - - // Effects: If there are no assets left for the recipient to withdraw, mark the stream as depleted. - if (recipientAmount == 0) { - _streams[streamId].isDepleted = true; - } - - // Effects: set the refunded amount. - _streams[streamId].amounts.refunded = senderAmount; - - // Retrieve the sender and the recipient from storage. - 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. - asset.safeTransfer({ to: sender, value: senderAmount }); - - // Log the cancellation. - 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 ISablierV2Recipient(recipient).onLockupStreamCanceled({ - streamId: streamId, - sender: sender, - senderAmount: senderAmount, - recipientAmount: recipientAmount - }) { } catch { } - } - } - /// @dev See the documentation for the user-facing functions that call this internal function. function _createWithTimestamps(LockupDynamic.CreateWithTimestamps memory params) internal @@ -552,24 +331,24 @@ contract SablierV2LockupDynamic is streamId = nextStreamId; // Effects: create the stream. - LockupDynamic.Stream storage stream = _streams[streamId]; + Lockup.Stream storage stream = _streams[streamId]; stream.amounts.deposited = createAmounts.deposit; stream.asset = params.asset; stream.isCancelable = params.cancelable; stream.isTransferable = params.transferable; stream.isStream = true; stream.sender = params.sender; + stream.startTime = params.startTime; unchecked { // The segment count cannot be zero at this point. uint256 segmentCount = params.segments.length; stream.endTime = params.segments[segmentCount - 1].timestamp; - stream.startTime = params.startTime; // Effects: store the segments. Since Solidity lacks a syntax for copying arrays directly from // memory to storage, a manual approach is necessary. See https://github.com/ethereum/solidity/issues/12783. for (uint256 i = 0; i < segmentCount; ++i) { - stream.segments.push(params.segments[i]); + _segments[streamId].push(params.segments[i]); } // Effects: bump the next stream id and record the protocol fee. @@ -611,43 +390,4 @@ contract SablierV2LockupDynamic is broker: params.broker.account }); } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _renounce(uint256 streamId) internal override { - // Checks: the stream is cancelable. - if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); - } - - // Effects: renounce the stream by making it not cancelable. - _streams[streamId].isCancelable = false; - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdraw(uint256 streamId, address to, uint128 amount) internal override { - // Effects: update the withdrawn amount. - _streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount; - - // Retrieve the amounts from storage. - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - // Using ">=" instead of "==" for additional safety reasons. In the event of an unforeseen increase in the - // withdrawn amount, the stream will still be marked as depleted. - if (amounts.withdrawn >= amounts.deposited - amounts.refunded) { - // Effects: mark the stream as depleted. - _streams[streamId].isDepleted = true; - - // Effects: make the stream not cancelable anymore, because a depleted stream cannot be canceled. - _streams[streamId].isCancelable = false; - } - - // Retrieve the ERC-20 asset from storage. - IERC20 asset = _streams[streamId].asset; - - // Interactions: perform the ERC-20 transfer. - asset.safeTransfer({ to: to, value: amount }); - - // Log the withdrawal. - emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount); - } } diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index d359ba790..6a89afdd8 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -6,13 +6,11 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; -import { ISablierV2Lockup } from "./interfaces/ISablierV2Lockup.sol"; import { ISablierV2LockupLinear } from "./interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; -import { ISablierV2Recipient } from "./interfaces/hooks/ISablierV2Recipient.sol"; -import { Errors } from "./libraries/Errors.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupLinear } from "./types/DataTypes.sol"; @@ -46,8 +44,8 @@ contract SablierV2LockupLinear is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @dev Sablier V2 Lockup Linear streams mapped by unsigned integers. - mapping(uint256 id => LockupLinear.Stream stream) private _streams; + /// @dev Cliff times mapped by stream ids. + mapping(uint256 id => uint40 cliff) internal _cliffs; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -72,30 +70,9 @@ contract SablierV2LockupLinear is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Lockup - function getAsset(uint256 streamId) external view override notNull(streamId) returns (IERC20 asset) { - asset = _streams[streamId].asset; - } - /// @inheritdoc ISablierV2LockupLinear function getCliffTime(uint256 streamId) external view override notNull(streamId) returns (uint40 cliffTime) { - cliffTime = _streams[streamId].cliffTime; - } - - /// @inheritdoc ISablierV2Lockup - function getDepositedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 depositedAmount) - { - depositedAmount = _streams[streamId].amounts.deposited; - } - - /// @inheritdoc ISablierV2Lockup - function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime) { - endTime = _streams[streamId].endTime; + cliffTime = _cliffs[streamId]; } /// @inheritdoc ISablierV2LockupLinear @@ -108,141 +85,48 @@ contract SablierV2LockupLinear is { range = LockupLinear.Range({ start: _streams[streamId].startTime, - cliff: _streams[streamId].cliffTime, + cliff: _cliffs[streamId], end: _streams[streamId].endTime }); } - /// @inheritdoc ISablierV2Lockup - function getRefundedAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundedAmount) - { - refundedAmount = _streams[streamId].amounts.refunded; - } - - /// @inheritdoc ISablierV2Lockup - function getSender(uint256 streamId) - public - view - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (address sender) - { - sender = _streams[streamId].sender; - } - - /// @inheritdoc ISablierV2Lockup - function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime) { - startTime = _streams[streamId].startTime; - } - /// @inheritdoc ISablierV2LockupLinear function getStream(uint256 streamId) external view override notNull(streamId) - returns (LockupLinear.Stream memory stream) + returns (LockupLinear.StreamLL memory stream) { - stream = _streams[streamId]; + Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. if (_statusOf(streamId) == Lockup.Status.SETTLED) { - stream.isCancelable = false; + lockupStream.isCancelable = false; } - } - /// @inheritdoc ISablierV2Lockup - function getWithdrawnAmount(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 withdrawnAmount) - { - withdrawnAmount = _streams[streamId].amounts.withdrawn; - } - - /// @inheritdoc ISablierV2Lockup - function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result) { - if (_statusOf(streamId) != Lockup.Status.SETTLED) { - result = _streams[streamId].isCancelable; - } - } - - /// @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 - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (bool result) - { - result = _streams[streamId].isDepleted; - } - - /// @inheritdoc ISablierV2Lockup - function isStream(uint256 streamId) public view override(ISablierV2Lockup, SablierV2Lockup) returns (bool result) { - result = _streams[streamId].isStream; - } - - /// @inheritdoc ISablierV2Lockup - function refundableAmountOf(uint256 streamId) - external - view - override - notNull(streamId) - returns (uint128 refundableAmount) - { - // These checks are needed because {_calculateStreamedAmount} does not look up the stream's status. Note that - // checking for `isCancelable` also checks if the stream `wasCanceled` thanks to the protocol invariant that - // canceled streams are not cancelable anymore. - if (_streams[streamId].isCancelable && !_streams[streamId].isDepleted) { - refundableAmount = _streams[streamId].amounts.deposited - _calculateStreamedAmount(streamId); - } - // Otherwise, the result is implicitly zero. - } - - /// @inheritdoc ISablierV2Lockup - function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status) { - status = _statusOf(streamId); + stream = LockupLinear.StreamLL({ + amounts: lockupStream.amounts, + asset: lockupStream.asset, + cliffTime: _cliffs[streamId], + endTime: lockupStream.endTime, + isCancelable: lockupStream.isCancelable, + isTransferable: lockupStream.isTransferable, + isDepleted: lockupStream.isDepleted, + isStream: lockupStream.isStream, + sender: lockupStream.sender, + startTime: lockupStream.startTime, + wasCanceled: lockupStream.wasCanceled + }); } - /// @inheritdoc ISablierV2LockupLinear function streamedAmountOf(uint256 streamId) public view - override(ISablierV2Lockup, ISablierV2LockupLinear) - notNull(streamId) - returns (uint128 streamedAmount) - { - streamedAmount = _streamedAmountOf(streamId); - } - - /// @inheritdoc ISablierV2Lockup - function wasCanceled(uint256 streamId) - public - view - override(ISablierV2Lockup, SablierV2Lockup) - notNull(streamId) - returns (bool result) + override(SablierV2Lockup, ISablierV2LockupLinear) + returns (uint128) { - result = _streams[streamId].wasCanceled; + return super.streamedAmountOf(streamId); } /*////////////////////////////////////////////////////////////////////////// @@ -262,11 +146,12 @@ contract SablierV2LockupLinear is // Calculate the cliff time and the end time. It is safe to use unchecked arithmetic because // {_createWithTimestamps} will nonetheless check that the end time is greater than the cliff time, - // and also that the cliff time is greater than or equal to the start time. + // and also that the cliff time, if set, is greater than or equal to the start time. unchecked { - range.cliff = range.start + params.durations.cliff; + range.cliff = params.durations.cliff > 0 ? range.start + params.durations.cliff : 0; range.end = range.start + params.durations.total; } + // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( LockupLinear.CreateWithTimestamps({ @@ -297,10 +182,10 @@ contract SablierV2LockupLinear is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Calculates the streamed amount without looking up the stream's status. - function _calculateStreamedAmount(uint256 streamId) internal view returns (uint128) { + /// @inheritdoc SablierV2Lockup + function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the cliff time is in the future, return zero. - uint256 cliffTime = uint256(_streams[streamId].cliffTime); + uint256 cliffTime = uint256(_cliffs[streamId]); uint256 currentTime = block.timestamp; if (cliffTime > currentTime) { return 0; @@ -341,116 +226,10 @@ contract SablierV2LockupLinear is } } - /// @inheritdoc SablierV2Lockup - function _isCallerStreamSender(uint256 streamId) internal view override returns (bool) { - return msg.sender == _streams[streamId].sender; - } - - /// @inheritdoc SablierV2Lockup - function _statusOf(uint256 streamId) internal view override returns (Lockup.Status) { - if (_streams[streamId].isDepleted) { - return Lockup.Status.DEPLETED; - } else if (_streams[streamId].wasCanceled) { - return Lockup.Status.CANCELED; - } - - if (block.timestamp < _streams[streamId].startTime) { - return Lockup.Status.PENDING; - } - - if (_calculateStreamedAmount(streamId) < _streams[streamId].amounts.deposited) { - return Lockup.Status.STREAMING; - } else { - return Lockup.Status.SETTLED; - } - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _streamedAmountOf(uint256 streamId) internal view returns (uint128) { - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - if (_streams[streamId].isDepleted) { - return amounts.withdrawn; - } else if (_streams[streamId].wasCanceled) { - return amounts.deposited - amounts.refunded; - } - - return _calculateStreamedAmount(streamId); - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdrawableAmountOf(uint256 streamId) internal view override returns (uint128) { - return _streamedAmountOf(streamId) - _streams[streamId].amounts.withdrawn; - } - /*////////////////////////////////////////////////////////////////////////// INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev See the documentation for the user-facing functions that call this internal function. - function _cancel(uint256 streamId) internal override { - // Calculate the streamed amount. - uint128 streamedAmount = _calculateStreamedAmount(streamId); - - // Retrieve the amounts from storage. - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - // Checks: the stream is not settled. - if (streamedAmount >= amounts.deposited) { - revert Errors.SablierV2Lockup_StreamSettled(streamId); - } - - // Checks: the stream is cancelable. - if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); - } - - // Calculate the sender's and the recipient's amount. - uint128 senderAmount = amounts.deposited - streamedAmount; - uint128 recipientAmount = streamedAmount - amounts.withdrawn; - - // Effects: mark the stream as canceled. - _streams[streamId].wasCanceled = true; - - // Effects: make the stream not cancelable anymore, because a stream can only be canceled once. - _streams[streamId].isCancelable = false; - - // Effects: If there are no assets left for the recipient to withdraw, mark the stream as depleted. - if (recipientAmount == 0) { - _streams[streamId].isDepleted = true; - } - - // Effects: set the refunded amount. - _streams[streamId].amounts.refunded = senderAmount; - - // Retrieve the sender and the recipient from storage. - 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. - asset.safeTransfer({ to: sender, value: senderAmount }); - - // Log the cancellation. - 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 ISablierV2Recipient(recipient).onLockupStreamCanceled({ - streamId: streamId, - sender: sender, - senderAmount: senderAmount, - recipientAmount: recipientAmount - }) { } catch { } - } - } - /// @dev See the documentation for the user-facing functions that call this internal function. function _createWithTimestamps(LockupLinear.CreateWithTimestamps memory params) internal @@ -471,10 +250,9 @@ contract SablierV2LockupLinear is streamId = nextStreamId; // Effects: create the stream. - _streams[streamId] = LockupLinear.Stream({ + _streams[streamId] = Lockup.Stream({ amounts: Lockup.Amounts({ deposited: createAmounts.deposit, refunded: 0, withdrawn: 0 }), asset: params.asset, - cliffTime: params.range.cliff, endTime: params.range.end, isCancelable: params.cancelable, isTransferable: params.transferable, @@ -485,6 +263,11 @@ contract SablierV2LockupLinear is wasCanceled: false }); + // Effects: set the cliff time if it is greater than 0. + if (params.range.cliff > 0) { + _cliffs[streamId] = params.range.cliff; + } + // Effects: bump the next stream id and record the protocol fee. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. unchecked { @@ -524,43 +307,4 @@ contract SablierV2LockupLinear is broker: params.broker.account }); } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _renounce(uint256 streamId) internal override { - // Checks: the stream is cancelable. - if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); - } - - // Effects: renounce the stream by making it not cancelable. - _streams[streamId].isCancelable = false; - } - - /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdraw(uint256 streamId, address to, uint128 amount) internal override { - // Effects: update the withdrawn amount. - _streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount; - - // Retrieve the amounts from storage. - Lockup.Amounts memory amounts = _streams[streamId].amounts; - - // Using ">=" instead of "==" for additional safety reasons. In the event of an unforeseen increase in the - // withdrawn amount, the stream will still be marked as depleted. - if (amounts.withdrawn >= amounts.deposited - amounts.refunded) { - // Effects: mark the stream as depleted. - _streams[streamId].isDepleted = true; - - // Effects: make the stream not cancelable anymore, because a depleted stream cannot be canceled. - _streams[streamId].isCancelable = false; - } - - // Retrieve the ERC-20 asset from storage. - IERC20 asset = _streams[streamId].asset; - - // Interactions: perform the ERC-20 transfer. - asset.safeTransfer({ to: to, value: amount }); - - // Log the withdrawal. - emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount); - } } diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 93301d4c0..47ef57fff 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.22; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; @@ -22,6 +24,8 @@ abstract contract SablierV2Lockup is ISablierV2Lockup, // 4 inherited components ERC721 // 6 inherited components { + using SafeERC20 for IERC20; + /*////////////////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ @@ -32,6 +36,9 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup ISablierV2NFTDescriptor public override nftDescriptor; + /// @dev Sablier V2 Lockup streams mapped by unsigned integers. + mapping(uint256 id => Lockup.Stream stream) internal _streams; + /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -55,7 +62,7 @@ abstract contract SablierV2Lockup is /// @dev Checks that `streamId` does not reference a null stream. modifier notNull(uint256 streamId) { - if (!isStream(streamId)) { + if (!_streams[streamId].isStream) { revert Errors.SablierV2Lockup_Null(streamId); } _; @@ -71,14 +78,71 @@ abstract contract SablierV2Lockup is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierV2Lockup + function getAsset(uint256 streamId) external view override notNull(streamId) returns (IERC20 asset) { + asset = _streams[streamId].asset; + } + + /// @inheritdoc ISablierV2Lockup + function getDepositedAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 depositedAmount) + { + depositedAmount = _streams[streamId].amounts.deposited; + } + + /// @inheritdoc ISablierV2Lockup + function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime) { + endTime = _streams[streamId].endTime; + } + /// @inheritdoc ISablierV2Lockup function getRecipient(uint256 streamId) external view override returns (address recipient) { - // Checks: the stream NFT exists, and return the owner, which is the stream's recipient. + // Checks: the stream NFT exists and return the owner, which is the stream's recipient. recipient = _requireOwned({ tokenId: streamId }); } /// @inheritdoc ISablierV2Lockup - function getSender(uint256 streamId) public view virtual override returns (address sender); + function getRefundedAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 refundedAmount) + { + refundedAmount = _streams[streamId].amounts.refunded; + } + + /// @inheritdoc ISablierV2Lockup + function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender) { + sender = _streams[streamId].sender; + } + + /// @inheritdoc ISablierV2Lockup + function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime) { + startTime = _streams[streamId].startTime; + } + + /// @inheritdoc ISablierV2Lockup + function getWithdrawnAmount(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 withdrawnAmount) + { + withdrawnAmount = _streams[streamId].amounts.withdrawn; + } + + /// @inheritdoc ISablierV2Lockup + function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result) { + if (_statusOf(streamId) != Lockup.Status.SETTLED) { + result = _streams[streamId].isCancelable; + } + } /// @inheritdoc ISablierV2Lockup function isCold(uint256 streamId) external view override notNull(streamId) returns (bool result) { @@ -87,10 +151,19 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - function isDepleted(uint256 streamId) public view virtual override returns (bool result); + function isDepleted(uint256 streamId) external view override notNull(streamId) returns (bool result) { + result = _streams[streamId].isDepleted; + } /// @inheritdoc ISablierV2Lockup - function isStream(uint256 streamId) public view virtual override returns (bool result); + function isStream(uint256 streamId) external view override returns (bool result) { + result = _streams[streamId].isStream; + } + + /// @inheritdoc ISablierV2Lockup + function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result) { + result = _streams[streamId].isTransferable; + } /// @inheritdoc ISablierV2Lockup function isWarm(uint256 streamId) external view override notNull(streamId) returns (bool result) { @@ -98,6 +171,40 @@ abstract contract SablierV2Lockup is result = status == Lockup.Status.PENDING || status == Lockup.Status.STREAMING; } + /// @inheritdoc ISablierV2Lockup + function refundableAmountOf(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 refundableAmount) + { + // These checks are needed because {_calculateStreamedAmount} does not look up the stream's status. Note that + // checking for `isCancelable` also checks if the stream `wasCanceled` thanks to the protocol invariant that + // canceled streams are not cancelable anymore. + if (_streams[streamId].isCancelable && !_streams[streamId].isDepleted) { + refundableAmount = _streams[streamId].amounts.deposited - _calculateStreamedAmount(streamId); + } + // Otherwise, the result is implicitly zero. + } + + /// @inheritdoc ISablierV2Lockup + function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status) { + status = _statusOf(streamId); + } + + /// @inheritdoc ISablierV2Lockup + function streamedAmountOf(uint256 streamId) + public + view + virtual + override + notNull(streamId) + returns (uint128 streamedAmount) + { + streamedAmount = _streamedAmountOf(streamId); + } + /// @inheritdoc ERC721 function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri) { // Checks: the stream NFT exists. @@ -108,7 +215,9 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - function wasCanceled(uint256 streamId) public view virtual override returns (bool result); + function wasCanceled(uint256 streamId) external view override notNull(streamId) returns (bool result) { + result = _streams[streamId].wasCanceled; + } /// @inheritdoc ISablierV2Lockup function withdrawableAmountOf(uint256 streamId) @@ -121,17 +230,14 @@ abstract contract SablierV2Lockup is withdrawableAmount = _withdrawableAmountOf(streamId); } - /// @inheritdoc ISablierV2Lockup - function isTransferable(uint256 streamId) public view virtual returns (bool); - /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierV2Lockup - function burn(uint256 streamId) external override noDelegateCall { - // Checks: only depleted streams can be burned. This also checks that the stream is not null. - if (!isDepleted(streamId)) { + function burn(uint256 streamId) external override noDelegateCall notNull(streamId) { + // Checks: only depleted streams can be burned. + if (!_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamNotDepleted(streamId); } @@ -147,11 +253,11 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - 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)) { + function cancel(uint256 streamId) public override noDelegateCall notNull(streamId) { + // Checks: the stream is neither depleted nor canceled. + if (_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); - } else if (wasCanceled(streamId)) { + } else if (_streams[streamId].wasCanceled) { revert Errors.SablierV2Lockup_StreamCanceled(streamId); } @@ -231,10 +337,11 @@ abstract contract SablierV2Lockup is public override noDelegateCall + notNull(streamId) updateMetadata(streamId) { - // Checks: the stream is not depleted. This also checks that the stream is not null. - if (isDepleted(streamId)) { + // Checks: the stream is not depleted. + if (_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); } @@ -264,7 +371,7 @@ abstract contract SablierV2Lockup is } // Retrieve the sender from storage. - address sender = getSender(streamId); + address sender = _streams[streamId].sender; // Effects and Interactions: make the withdrawal. _withdraw(streamId, to, amount); @@ -352,6 +459,10 @@ abstract contract SablierV2Lockup is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Calculates the streamed amount of the stream without looking up the stream's status, which is + /// implemented by child contracts, it can vary depending on the model. + function _calculateStreamedAmount(uint256 streamId) internal view virtual returns (uint128); + /// @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) { @@ -362,10 +473,41 @@ abstract contract SablierV2Lockup is /// @notice Checks whether `msg.sender` is the stream's sender. /// @param streamId The stream id for the query. - function _isCallerStreamSender(uint256 streamId) internal view virtual returns (bool); + function _isCallerStreamSender(uint256 streamId) internal view returns (bool) { + return msg.sender == _streams[streamId].sender; + } /// @dev Retrieves the stream's status without performing a null check. - function _statusOf(uint256 streamId) internal view virtual returns (Lockup.Status); + function _statusOf(uint256 streamId) internal view returns (Lockup.Status) { + if (_streams[streamId].isDepleted) { + return Lockup.Status.DEPLETED; + } else if (_streams[streamId].wasCanceled) { + return Lockup.Status.CANCELED; + } + + if (block.timestamp < _streams[streamId].startTime) { + return Lockup.Status.PENDING; + } + + if (_calculateStreamedAmount(streamId) < _streams[streamId].amounts.deposited) { + return Lockup.Status.STREAMING; + } else { + return Lockup.Status.SETTLED; + } + } + + /// @dev See the documentation for the user-facing functions that call this internal function. + function _streamedAmountOf(uint256 streamId) internal view returns (uint128) { + Lockup.Amounts memory amounts = _streams[streamId].amounts; + + if (_streams[streamId].isDepleted) { + return amounts.withdrawn; + } else if (_streams[streamId].wasCanceled) { + return amounts.deposited - amounts.refunded; + } + + return _calculateStreamedAmount(streamId); + } /// @notice Overrides the internal ERC-721 `_update` function to check that the stream is transferable and emit /// an ERC-4906 event. @@ -389,7 +531,7 @@ abstract contract SablierV2Lockup is { address from = _ownerOf(streamId); - if (!isTransferable(streamId) && from != address(0) && to != address(0)) { + if (!_streams[streamId].isTransferable && from != address(0) && to != address(0)) { revert Errors.SablierV2Lockup_NotTransferable(streamId); } @@ -397,18 +539,114 @@ abstract contract SablierV2Lockup is } /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdrawableAmountOf(uint256 streamId) internal view virtual returns (uint128); + function _withdrawableAmountOf(uint256 streamId) internal view returns (uint128) { + return _streamedAmountOf(streamId) - _streams[streamId].amounts.withdrawn; + } /*////////////////////////////////////////////////////////////////////////// INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @dev See the documentation for the user-facing functions that call this internal function. - function _cancel(uint256 tokenId) internal virtual; + function _cancel(uint256 streamId) internal { + // Calculate the streamed amount. + uint128 streamedAmount = _calculateStreamedAmount(streamId); + + // Retrieve the amounts from storage. + Lockup.Amounts memory amounts = _streams[streamId].amounts; + + // Checks: the stream is not settled. + if (streamedAmount >= amounts.deposited) { + revert Errors.SablierV2Lockup_StreamSettled(streamId); + } + + // Checks: the stream is cancelable. + if (!_streams[streamId].isCancelable) { + revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); + } + + // Calculate the sender's and the recipient's amount. + uint128 senderAmount = amounts.deposited - streamedAmount; + uint128 recipientAmount = streamedAmount - amounts.withdrawn; + + // Effects: mark the stream as canceled. + _streams[streamId].wasCanceled = true; + + // Effects: make the stream not cancelable anymore, because a stream can only be canceled once. + _streams[streamId].isCancelable = false; + + // Effects: If there are no assets left for the recipient to withdraw, mark the stream as depleted. + if (recipientAmount == 0) { + _streams[streamId].isDepleted = true; + } + + // Effects: set the refunded amount. + _streams[streamId].amounts.refunded = senderAmount; + + // Retrieve the sender and the recipient from storage. + 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. + asset.safeTransfer({ to: sender, value: senderAmount }); + + // Log the cancellation. + 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 ISablierV2Recipient(recipient).onLockupStreamCanceled({ + streamId: streamId, + sender: sender, + senderAmount: senderAmount, + recipientAmount: recipientAmount + }) { } catch { } + } + } /// @dev See the documentation for the user-facing functions that call this internal function. - function _renounce(uint256 streamId) internal virtual; + function _renounce(uint256 streamId) internal { + // Checks: the stream is cancelable. + if (!_streams[streamId].isCancelable) { + revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); + } + + // Effects: renounce the stream by making it not cancelable. + _streams[streamId].isCancelable = false; + } /// @dev See the documentation for the user-facing functions that call this internal function. - function _withdraw(uint256 streamId, address to, uint128 amount) internal virtual; + function _withdraw(uint256 streamId, address to, uint128 amount) internal { + // Effects: update the withdrawn amount. + _streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount; + + // Retrieve the amounts from storage. + Lockup.Amounts memory amounts = _streams[streamId].amounts; + + // Using ">=" instead of "==" for additional safety reasons. In the event of an unforeseen increase in the + // withdrawn amount, the stream will still be marked as depleted. + if (amounts.withdrawn >= amounts.deposited - amounts.refunded) { + // Effects: mark the stream as depleted. + _streams[streamId].isDepleted = true; + + // Effects: make the stream not cancelable anymore, because a depleted stream cannot be canceled. + _streams[streamId].isCancelable = false; + } + + // Retrieve the ERC-20 asset from storage. + IERC20 asset = _streams[streamId].asset; + + // Interactions: perform the ERC-20 transfer. + asset.safeTransfer({ to: to, value: amount }); + + // Log the withdrawal. + emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount); + } } diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index 8f646cec3..ef6e68ea9 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -59,10 +59,10 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @param streamId The stream id for the query. function getSegments(uint256 streamId) external view returns (LockupDynamic.Segment[] memory segments); - /// @notice Retrieves the stream entity. + /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream id for the query. - function getStream(uint256 streamId) external view returns (LockupDynamic.Stream memory stream); + function getStream(uint256 streamId) external view returns (LockupDynamic.StreamLD memory stream); /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. /// diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index a8f066896..f2a5fdd7c 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -43,7 +43,8 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the stream's cliff time, which is a Unix timestamp. + /// @notice Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there + /// is no cliff. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream id for the query. function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); @@ -54,10 +55,10 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param streamId The stream id for the query. function getRange(uint256 streamId) external view returns (LockupLinear.Range memory range); - /// @notice Retrieves the stream entity. + /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream id for the query. - function getStream(uint256 streamId) external view returns (LockupLinear.Stream memory stream); + function getStream(uint256 streamId) external view returns (LockupLinear.StreamLL memory stream); /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. /// @@ -106,14 +107,17 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @dev Emits a {Transfer} and {CreateLockupLinearStream} event. /// /// Notes: + /// - A cliff time of zero means there is no cliff. /// - As long as the times are ordered, it is not an error for the start or the cliff time to be in the past. /// /// Requirements: /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. - /// - `params.range.start` must be less than or equal to `params.range.cliff`. - /// - `params.range.cliff` must be less than `params.range.end`. + /// - `params.range.start` must be greater than zero. + /// - `params.range.start` must be less than `params.range.end`. + /// - If set, `params.range.cliff` must be greater than `params.range.start`. + /// - If set, `params.range.cliff` must be less than `params.range.end`. /// - `params.range.end` must be in the future. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 278c43f8b..dd7c6ad57 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -116,7 +116,13 @@ library Errors { error SablierV2LockupLinear_CliffTimeNotLessThanEndTime(uint40 cliffTime, uint40 endTime); /// @notice Thrown when trying to create a stream with a start time greater than the cliff time. - error SablierV2LockupLinear_StartTimeGreaterThanCliffTime(uint40 startTime, uint40 cliffTime); + error SablierV2LockupLinear_StartTimeNotLessThanCliffTime(uint40 startTime, uint40 cliffTime); + + /// @notice Thrown when trying to create a stream with a start time greater than the end time. + error SablierV2LockupLinear_StartTimeNotLessThanEndTime(uint40 startTime, uint40 endTime); + + /// @notice Thrown when trying to create a stream with a start time equal to zero. + error SablierV2LockupLinear_StartTimeZero(); /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-NFT-DESCRIPTOR diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 73ee41f34..894ccf27a 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -92,9 +92,19 @@ library Helpers { revert Errors.SablierV2Lockup_DepositAmountZero(); } - // Checks: the start time is less than or equal to the cliff time. - if (range.start > range.cliff) { - revert Errors.SablierV2LockupLinear_StartTimeGreaterThanCliffTime(range.start, range.cliff); + // Checks: the start time is not zero. + if (range.start == 0) { + revert Errors.SablierV2LockupLinear_StartTimeZero(); + } + + // Checks: the start time is strictly less than the end time. + if (range.start >= range.end) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(range.start, range.end); + } + + // Checks: the start time is strictly less than the cliff time when cliff time is not zero. + if (range.cliff > 0 && range.start >= range.cliff) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(range.start, range.cliff); } // Checks: the cliff time is strictly less than the end time. diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 543e8de4e..f024ae71c 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -66,6 +66,35 @@ library Lockup { CANCELED, DEPLETED } + + /// @notice A common data structure to be stored in all child contracts of {SablierV2Lockup}. + /// @dev The fields are arranged like this to save gas via tight variable packing. + /// @param sender The address streaming the assets, with the ability to cancel the stream. + /// @param startTime The Unix timestamp indicating the stream's start. + /// @param endTime The Unix timestamp indicating the stream's end. + /// @param isCancelable Boolean indicating if the stream is cancelable. + /// @param wasCanceled Boolean indicating if the stream was canceled. + /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param isDepleted Boolean indicating if the stream is depleted. + /// @param isStream Boolean indicating if the struct entity exists. + /// @param isTransferable Boolean indicating if the stream NFT is transferable. + /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the + /// asset's decimals. + struct Stream { + // slot 0 + address sender; + uint40 startTime; + uint40 endTime; + bool isCancelable; + bool wasCanceled; + // slot 1 + IERC20 asset; + bool isDepleted; + bool isStream; + bool isTransferable; + // slot 2 and 3 + Lockup.Amounts amounts; + } } /// @notice Namespace for the structs used in {SablierV2LockupDynamic}. @@ -149,35 +178,20 @@ library LockupDynamic { uint40 duration; } - /// @notice Lockup Dynamic stream. - /// @dev The fields are arranged like this to save gas via tight variable packing. - /// @param sender The address streaming the assets, with the ability to cancel the stream. - /// @param startTime The Unix timestamp indicating the stream's start. - /// @param endTime The Unix timestamp indicating the stream's end. - /// @param isCancelable Boolean indicating if the stream is cancelable. - /// @param wasCanceled Boolean indicating if the stream was canceled. - /// @param asset The contract address of the ERC-20 asset used for streaming. - /// @param isDepleted Boolean indicating if the stream is depleted. - /// @param isStream Boolean indicating if the struct entity exists. - /// @param isTransferable Boolean indicating if the stream NFT is transferable. - /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the - /// asset's decimals. - /// @param segments Segments used to compose the custom streaming curve. - struct Stream { - // slot 0 + /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within + /// one call to the contract. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the segments. + struct StreamLD { address sender; uint40 startTime; uint40 endTime; bool isCancelable; bool wasCanceled; - // slot 1 IERC20 asset; bool isDepleted; bool isStream; bool isTransferable; - // slot 2 and 3 Lockup.Amounts amounts; - // slots [4..n] Segment[] segments; } } @@ -241,7 +255,7 @@ library LockupLinear { /// @notice Struct encapsulating the time range. /// @param start The Unix timestamp for the stream's start. - /// @param cliff The Unix timestamp for the cliff period's end. + /// @param cliff The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. /// @param end The Unix timestamp for the stream's end. struct Range { uint40 start; @@ -249,34 +263,20 @@ library LockupLinear { uint40 end; } - /// @notice Lockup Linear stream. - /// @dev The fields are arranged like this to save gas via tight variable packing. - /// @param sender The address streaming the assets, with the ability to cancel the stream. - /// @param startTime The Unix timestamp indicating the stream's start. - /// @param cliffTime The Unix timestamp indicating the cliff period's end. - /// @param isCancelable Boolean indicating if the stream is cancelable. - /// @param wasCanceled Boolean indicating if the stream was canceled. - /// @param asset The contract address of the ERC-20 asset used for streaming. - /// @param endTime The Unix timestamp indicating the stream's end. - /// @param isDepleted Boolean indicating if the stream is depleted. - /// @param isStream Boolean indicating if the struct entity exists. - /// @param isTransferable Boolean indicating if the stream NFT is transferable. - /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the - /// asset's decimals. - struct Stream { - // slot 0 + /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within + /// one call to the contract. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the cliff value. + struct StreamLL { address sender; uint40 startTime; - uint40 cliffTime; bool isCancelable; bool wasCanceled; - // slot 1 IERC20 asset; uint40 endTime; bool isDepleted; bool isStream; bool isTransferable; - // slot 2 and 3 Lockup.Amounts amounts; + uint40 cliffTime; } } diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 931e565a0..b9a983c4a 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -197,7 +197,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(vars.streamId); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, ASSET, "asset"); assertEq(actualStream.endTime, vars.range.end, "endTime"); diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index d390e49d0..65247b60a 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -121,7 +121,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); params.range.start = boundUint40(params.range.start, currentTime - 1000 seconds, currentTime + 10_000 seconds); - params.range.cliff = boundUint40(params.range.cliff, params.range.start, params.range.start + 52 weeks); + params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); params.transferable = true; @@ -193,7 +193,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { ); // Assert that the stream has been created. - LockupLinear.Stream memory actualStream = lockupLinear.getStream(vars.streamId); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, ASSET, "asset"); assertEq(actualStream.cliffTime, params.range.cliff, "cliffTime"); diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 41d2449b6..4ae6afc20 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -171,8 +171,8 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithDurations(); // Assert that the stream has been created. - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.Stream memory expectedStream = defaults.lockupDynamicStream(); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); expectedStream.endTime = range.end; expectedStream.segments = segments; expectedStream.startTime = range.start; diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 75ad84408..524a69d30 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -383,8 +383,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is streamId = createDefaultStreamWithAsset(IERC20(asset)); // Assert that the stream has been created. - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.Stream memory expectedStream = defaults.lockupDynamicStream(); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); expectedStream.asset = IERC20(asset); assertEq(actualStream, expectedStream); diff --git a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol index 0c9e1f110..50f3a75ac 100644 --- a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol @@ -26,8 +26,8 @@ contract GetStream_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Inte function test_GetStream_StatusSettled() external givenNotNull { vm.warp({ timestamp: defaults.END_TIME() }); - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(defaultStreamId); - LockupDynamic.Stream memory expectedStream = defaults.lockupDynamicStream(); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(defaultStreamId); + LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); expectedStream.isCancelable = false; assertEq(actualStream, expectedStream); } @@ -38,8 +38,8 @@ contract GetStream_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Inte function test_GetStream() external givenNotNull givenStatusNotSettled { uint256 streamId = createDefaultStream(); - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.Stream memory expectedStream = defaults.lockupDynamicStream(); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); assertEq(actualStream, expectedStream); } } diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 1268f5a57..1a5c5acd7 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -28,30 +28,6 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is expectRevertDueToDelegateCall(success, returnData); } - function test_RevertWhen_CliffDurationCalculationOverflows() external whenNotDelegateCalled { - uint40 startTime = getBlockTimestamp(); - uint40 cliffDuration = MAX_UINT40 - startTime + 1 seconds; - - // Calculate the end time. Needs to be "unchecked" to avoid an overflow. - uint40 cliffTime; - unchecked { - cliffTime = startTime + cliffDuration; - } - - // Expect the relevant error to be thrown. - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeGreaterThanCliffTime.selector, startTime, cliffTime - ) - ); - - // Set the total duration to be the same as the cliff duration. - uint40 totalDuration = cliffDuration; - - // Create the stream. - createDefaultStreamWithDurations(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); - } - function test_RevertWhen_TotalDurationCalculationOverflows() external whenNotDelegateCalled @@ -61,7 +37,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLinear.Durations memory durations = LockupLinear.Durations({ cliff: 0, total: MAX_UINT40 - startTime + 1 seconds }); - // Calculate the cliff time and the end time. Needs to be "unchecked" to avoid an overflow. + // Calculate the cliff time and the end time. Needs to be "unchecked" to allow an overflow. uint40 cliffTime; uint40 endTime; unchecked { @@ -72,7 +48,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime + Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime ) ); @@ -131,8 +107,8 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithDurations(); // Assert that the stream has been created. - LockupLinear.Stream memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.Stream memory expectedStream = defaults.lockupLinearStream(); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); expectedStream.startTime = range.start; expectedStream.cliffTime = range.cliff; expectedStream.endTime = range.end; diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree index ca9a10630..1b742b1c2 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree @@ -2,9 +2,6 @@ createWithDurations.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── when the cliff duration calculation overflows uint256 - │ └── it should revert due to the start time being greater than the cliff time - └── when the cliff duration calculation does not overflow uint256 ├── when the total duration calculation overflows uint256 │ └── it should revert └── when the total duration calculation does not overflow uint256 diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index f4b4b656a..25d952f72 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -46,18 +46,80 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithTotalAmount(0); } + function test_RevertWhen_StartTimeZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { + uint40 cliffTime = defaults.CLIFF_TIME(); + uint40 endTime = defaults.END_TIME(); + + vm.expectRevert(Errors.SablierV2LockupLinear_StartTimeZero.selector); + createDefaultStreamWithRange(LockupLinear.Range({ start: 0, cliff: cliffTime, end: endTime })); + } + + modifier whenCliffTimeZero() { + _; + } + + function test_RevertWhen_StartTimeGreaterThanEndTime() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenCliffTimeZero + { + uint40 startTime = defaults.END_TIME(); + uint40 endTime = defaults.START_TIME(); + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime + ) + ); + createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: 0, end: endTime })); + } + + function test_CreateWithTimestamps_CliffTimeZero() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenCliffTimeZero + { + createDefaultStreamWithRange( + LockupLinear.Range({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) + ); + + // Assert that the stream has been created. + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); + expectedStream.cliffTime = 0; + assertEq(actualStream, expectedStream); + + // Assert that the next stream id has been bumped. + uint256 actualNextStreamId = lockupLinear.nextStreamId(); + uint256 expectedNextStreamId = streamId + 1; + assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); + + // Assert that the NFT has been minted. + address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + address expectedNFTOwner = users.recipient; + assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); + } + + modifier whenCliffTimeGreaterThanZero() { + _; + } + function test_RevertWhen_StartTimeGreaterThanCliffTime() external whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero { uint40 startTime = defaults.CLIFF_TIME(); uint40 cliffTime = defaults.START_TIME(); uint40 endTime = defaults.END_TIME(); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeGreaterThanCliffTime.selector, startTime, cliffTime + Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime ) ); createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); @@ -68,6 +130,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime { uint40 startTime = defaults.START_TIME(); @@ -86,6 +149,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -101,6 +165,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -124,6 +189,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -139,6 +205,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -155,6 +222,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -169,6 +237,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is external whenNotDelegateCalled whenDepositAmountNotZero + whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture @@ -222,8 +291,8 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithAsset(IERC20(asset)); // Assert that the stream has been created. - LockupLinear.Stream memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.Stream memory expectedStream = defaults.lockupLinearStream(); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); expectedStream.asset = IERC20(asset); assertEq(actualStream, expectedStream); diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree index 407705603..e1537f793 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree @@ -8,38 +8,47 @@ createWithTimestamps.t.sol ├── when the deposit amount is zero │ └── it should revert └── when the deposit amount is not zero - ├── when the start time is greater than the cliff time + ├── when the start time is zero │ └── it should revert - └── when the start time is not greater than the cliff time - ├── when the cliff time is not less than the end time - │ └── it should revert - └── when the cliff time is less than the end time - ├── when the end time is not in the future + └── when the start time is not zero + ├── when the cliff time is zero + │ ├── when the start time is greater than the end time + │ │ └── it should revert + │ └── when the start time is not greater than the end time + │ └── it should create the stream + └── when the cliff time is greater than zero + ├── when the start time is not less than the cliff time │ └── it should revert - └── when the end time is in the future - ├── given the protocol fee is too high + └── when the start time is not greater than the cliff time + ├── when the cliff time is less than the end time │ └── it should revert - └── given the protocol fee is not too high - ├── when the broker fee is too high + └── when the cliff time is less than the end time + ├── when the end time is not in the future │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract + └── when the end time is in the future + ├── given the protocol fee is too high │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should record the protocol fee - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupLinearStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should record the protocol fee - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupLinearStream} event + └── given the protocol fee is not too high + ├── when the broker fee is too high + │ └── it should revert + └── when the broker fee is not too high + ├── when the asset is not a contract + │ └── it should revert + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should record the protocol fee + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupLinearStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should record the protocol fee + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupLinearStream} event diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol index eedcae912..0524c819c 100644 --- a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -26,8 +26,8 @@ contract GetStream_LockupLinear_Integration_Concrete_Test is LockupLinear_Integr function test_GetStream_StatusSettled() external givenNotNull { vm.warp({ timestamp: defaults.END_TIME() }); - LockupLinear.Stream memory actualStream = lockupLinear.getStream(defaultStreamId); - LockupLinear.Stream memory expectedStream = defaults.lockupLinearStream(); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(defaultStreamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); expectedStream.isCancelable = false; assertEq(actualStream, expectedStream); } @@ -37,8 +37,8 @@ contract GetStream_LockupLinear_Integration_Concrete_Test is LockupLinear_Integr } function test_GetStream() external givenNotNull givenStatusNotSettled { - LockupLinear.Stream memory actualStream = lockupLinear.getStream(defaultStreamId); - LockupLinear.Stream memory expectedStream = defaults.lockupLinearStream(); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(defaultStreamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); assertEq(actualStream, expectedStream); } } diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 7ceb58e9d..023157f3b 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -110,7 +110,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 861f34eb9..e2cad95c0 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -305,7 +305,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is vars.isCancelable = vars.isSettled ? false : params.cancelable; // Assert that the stream has been created. - LockupDynamic.Stream memory actualStream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index d6194802d..f9d2c440f 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -20,33 +20,6 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is CreateWithDurations_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_CliffDurationCalculationOverflows(uint40 cliffDuration) - external - whenNotDelegateCalled - { - uint40 startTime = getBlockTimestamp(); - cliffDuration = boundUint40(cliffDuration, MAX_UINT40 - startTime + 1 seconds, MAX_UINT40); - - // Calculate the end time. Needs to be "unchecked" to avoid an overflow. - uint40 cliffTime; - unchecked { - cliffTime = startTime + cliffDuration; - } - - // Expect the relevant error to be thrown. - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeGreaterThanCliffTime.selector, startTime, cliffTime - ) - ); - - // Set the total duration to be the same as the cliff duration. - uint40 totalDuration = cliffDuration; - - // Create the stream. - createDefaultStreamWithDurations(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); - } - function testFuzz_RevertWhen_TotalDurationCalculationOverflows(LockupLinear.Durations memory durations) external whenNotDelegateCalled @@ -56,7 +29,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is durations.cliff = boundUint40(durations.cliff, 0, MAX_UINT40 - startTime); durations.total = boundUint40(durations.total, MAX_UINT40 - startTime + 1 seconds, MAX_UINT40); - // Calculate the cliff time and the end time. Needs to be "unchecked" to avoid an overflow. + // Calculate the cliff time and the end time. Needs to be "unchecked" to allow an overflow. uint40 cliffTime; uint40 endTime; unchecked { @@ -67,7 +40,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime + Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime ) ); @@ -81,7 +54,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is whenCliffDurationCalculationDoesNotOverflow whenTotalDurationCalculationDoesNotOverflow { - durations.total = boundUint40(durations.total, 0, MAX_UNIX_TIMESTAMP); + durations.total = boundUint40(durations.total, 1, MAX_UNIX_TIMESTAMP); vm.assume(durations.cliff < durations.total); // Make the Sender the stream's funder (recall that the Sender is the default caller). @@ -103,7 +76,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Create the range struct by calculating the start time, cliff time and the end time. LockupLinear.Range memory range = LockupLinear.Range({ start: getBlockTimestamp(), - cliff: getBlockTimestamp() + durations.cliff, + cliff: durations.cliff == 0 ? 0 : getBlockTimestamp() + durations.cliff, end: getBlockTimestamp() + durations.total }); @@ -126,8 +99,8 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is createDefaultStreamWithDurations(durations); // Assert that the stream has been created. - LockupLinear.Stream memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.Stream memory expectedStream = defaults.lockupLinearStream(); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); expectedStream.cliffTime = range.cliff; expectedStream.endTime = range.end; expectedStream.startTime = range.start; diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 0e2e23baa..641e6bc50 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -28,10 +28,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenRecipientNonZeroAddress whenDepositAmountNotZero { - startTime = boundUint40(startTime, defaults.CLIFF_TIME() + 1 seconds, MAX_UNIX_TIMESTAMP); + startTime = boundUint40(startTime, defaults.CLIFF_TIME() + 1 seconds, defaults.END_TIME() - 1 seconds); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeGreaterThanCliffTime.selector, startTime, defaults.CLIFF_TIME() + Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() ) ); createDefaultStreamWithStartTime(startTime); @@ -48,7 +48,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenStartTimeNotGreaterThanCliffTime { uint40 startTime = defaults.START_TIME(); - endTime = boundUint40(endTime, startTime, startTime + 2 weeks); + endTime = boundUint40(endTime, startTime + 1, startTime + 2 weeks); cliffTime = boundUint40(cliffTime, endTime, MAX_UNIX_TIMESTAMP); vm.expectRevert( @@ -143,7 +143,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vm.assume(params.totalAmount != 0); params.range.start = boundUint40(params.range.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); - params.range.cliff = boundUint40(params.range.cliff, params.range.start, params.range.start + 52 weeks); + params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.range.end = boundUint40(params.range.end, params.range.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); protocolFee = _bound(protocolFee, 0, MAX_FEE); @@ -210,7 +210,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is ); // Assert that the stream has been created. - LockupLinear.Stream memory actualStream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.cliffTime, params.range.cliff, "cliffTime"); diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index 811db9f30..415586a7e 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -64,7 +64,7 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - LockupDynamic.Stream memory stream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory stream = lockupDynamic.getStream(streamId); assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); } } @@ -74,7 +74,7 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - LockupDynamic.Stream memory stream = lockupDynamic.getStream(streamId); + LockupDynamic.StreamLD memory stream = lockupDynamic.getStream(streamId); assertNotEq(stream.endTime, 0, "Invariant violated: end time zero"); } } diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index adb8b5db2..84ac74858 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -58,16 +58,18 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { INVARIANTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The cliff time must not be less than the start time. - function invariant_CliffTimeGteStartTime() external useCurrentTimestamp { + /// @dev The cliff time must be greater than the start time, if it is not zero. + function invariant_CliffTimeGtStartTimeOrZero() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( - lockupLinear.getCliffTime(streamId), - lockupLinear.getStartTime(streamId), - "Invariant violated: cliff time < start time" - ); + if (lockupLinear.getCliffTime(streamId) > 0) { + assertGt( + lockupLinear.getCliffTime(streamId), + lockupLinear.getStartTime(streamId), + "Invariant violated: cliff time <= start time" + ); + } } } @@ -76,7 +78,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - LockupLinear.Stream memory stream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory stream = lockupLinear.getStream(streamId); assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); } } @@ -99,7 +101,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - LockupLinear.Stream memory stream = lockupLinear.getStream(streamId); + LockupLinear.StreamLL memory stream = lockupLinear.getStream(streamId); assertNotEq(stream.endTime, 0, "Invariant violated: stream non-null, end time zero"); } } diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index 940b771ea..5aab6bfa6 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -94,8 +94,8 @@ contract LockupLinearCreateHandler is BaseHandler { uint40 currentTime = getBlockTimestamp(); params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - params.range.start = boundUint40(params.range.start, 0, currentTime); - params.range.cliff = boundUint40(params.range.cliff, params.range.start, params.range.start + 52 weeks); + params.range.start = boundUint40(params.range.start, 1, currentTime); + params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); // Bound the end time so that it is always greater than both the current time and the cliff time (this is diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 86b14ef04..05e6761b2 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -40,7 +40,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { } /// @dev Compares two {LockupLinear.Stream} struct entities. - function assertEq(LockupLinear.Stream memory a, LockupLinear.Stream memory b) internal { + function assertEq(LockupLinear.StreamLL memory a, LockupLinear.StreamLL memory b) internal { assertEq(a.amounts, b.amounts); assertEq(a.asset, b.asset, "asset"); assertEq(a.cliffTime, b.cliffTime, "cliffTime"); @@ -55,7 +55,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { } /// @dev Compares two {LockupDynamic.Stream} struct entities. - function assertEq(LockupDynamic.Stream memory a, LockupDynamic.Stream memory b) internal { + function assertEq(LockupDynamic.StreamLD memory a, LockupDynamic.StreamLD memory b) internal { assertEq(a.asset, b.asset, "asset"); assertEq(a.endTime, b.endTime, "endTime"); assertEq(a.isCancelable, b.isCancelable, "isCancelable"); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index c190854dc..7fad153ec 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -91,8 +91,8 @@ contract Defaults is Constants { return LockupDynamic.Range({ start: START_TIME, end: END_TIME }); } - function lockupDynamicStream() public view returns (LockupDynamic.Stream memory) { - return LockupDynamic.Stream({ + function lockupDynamicStream() public view returns (LockupDynamic.StreamLD memory) { + return LockupDynamic.StreamLD({ amounts: lockupAmounts(), asset: asset, endTime: END_TIME, @@ -111,8 +111,8 @@ contract Defaults is Constants { return LockupLinear.Range({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); } - function lockupLinearStream() public view returns (LockupLinear.Stream memory) { - return LockupLinear.Stream({ + function lockupLinearStream() public view returns (LockupLinear.StreamLL memory) { + return LockupLinear.StreamLL({ amounts: lockupAmounts(), asset: asset, cliffTime: CLIFF_TIME, From 90dfc225ec14de614519254a7e84735d4e89db72 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 20 Feb 2024 15:50:20 +0000 Subject: [PATCH 047/132] fix: avoid duplicate calls on withdraw hook when sender is also the recipient (#826) * fix: mitigate duplicate calls on withdraw hook when sender is recipient * test: add integration tests for withdraw hook calls * test: rename create default stream functions test: remove test headers test: rename withdrawHooks test functions test: add more modifiers in withdrawHooks tests * refactor: low priority to "sender != recipient" check for gas optimization test: rename modifiers name in withdrawHooks.t.sol test: refactor withdrawHooks.tree --------- Co-authored-by: andreivladbrg --- src/abstracts/SablierV2Lockup.sol | 8 +- .../lockup-dynamic/LockupDynamic.t.sol | 17 +- .../concrete/lockup-linear/LockupLinear.t.sol | 15 + .../lockup/withdraw-hooks/withdrawHooks.t.sol | 284 ++++++++++++++++++ .../lockup/withdraw-hooks/withdrawHooks.tree | 21 ++ .../concrete/lockup/withdraw/withdraw.t.sol | 14 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 15 + .../shared/lockup-linear/LockupLinear.t.sol | 15 + test/integration/shared/lockup/Lockup.t.sol | 14 + test/integration/shared/lockup/withdraw.t.sol | 8 + 10 files changed, 393 insertions(+), 18 deletions(-) create mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol create mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 47ef57fff..7da2fd231 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -388,10 +388,10 @@ abstract contract SablierV2Lockup is }) { } catch { } } - // Interactions: if `msg.sender` is not the sender and the sender 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 != sender && sender.code.length > 0) { + // Interactions: if `msg.sender` is not the sender, the sender is a contract and sender is different from the + // recipient, 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 != sender && sender.code.length > 0 && sender != recipient) { try ISablierV2Sender(sender).onLockupStreamWithdrawn({ streamId: streamId, caller: msg.sender, diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index f4e92bdde..697505783 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -31,8 +31,9 @@ import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptrol import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; +import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -434,6 +435,20 @@ contract Withdraw_LockupDynamic_Integration_Concrete_Test is } } +contract WithdrawHooks_LockupDynamic_Integration_Concrete_Test is + LockupDynamic_Integration_Concrete_Test, + WithdrawHooks_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupDynamic_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) + { + LockupDynamic_Integration_Concrete_Test.setUp(); + WithdrawHooks_Integration_Concrete_Test.setUp(); + } +} + contract WithdrawMax_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index 02a7b9c5b..e6540ba09 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -34,6 +34,7 @@ import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -435,6 +436,20 @@ contract Withdraw_LockupLinear_Integration_Concrete_Test is } } +contract WithdrawHooks_LockupLinear_Integration_Concrete_Test is + LockupLinear_Integration_Concrete_Test, + WithdrawHooks_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupLinear_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) + { + LockupLinear_Integration_Concrete_Test.setUp(); + WithdrawHooks_Integration_Concrete_Test.setUp(); + } +} + contract WithdrawMax_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol new file mode 100644 index 000000000..6b90a2054 --- /dev/null +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: UNLICENSED +// solhint-disable max-line-length +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; +import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; + +import { Integration_Test } from "../../../Integration.t.sol"; +import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; + +abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, Withdraw_Integration_Shared_Test { + function setUp() public virtual override(Integration_Test, Withdraw_Integration_Shared_Test) { + Withdraw_Integration_Shared_Test.setUp(); + } + + modifier givenDifferentSenderAndRecipient() { + _; + } + + function test_WithdrawHooks_CallerUnknown() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + address unknownCaller = address(0xCAFE); + + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make `unknownCaller` the caller in this test. + changePrank({ msgSender: unknownCaller }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, unknownCaller, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerApprovedOperator() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodRecipient) }); + lockup.approve({ to: users.operator, tokenId: streamId }); + + // Make the operator the caller in this test. + changePrank({ msgSender: users.operator }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, users.operator, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerSender() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make the sender the caller in this test. + changePrank({ msgSender: address(goodSender) }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 1 call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect 0 calls to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodRecipient), withdrawAmount) + ), + count: 0 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerRecipient() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make the recipient the caller in this test. + changePrank({ msgSender: address(goodRecipient) }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 0 calls to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) + ), + count: 0 + }); + + // Expect 1 call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + modifier givenSameSenderAndRecipient() { + _; + } + + function test_WithdrawHooks_SenderHook_CallerUnknown() external givenSenderContract givenSameSenderAndRecipient { + address unknownCaller = address(0xCAFE); + + // Create the stream with recipient which is same as the sender contract. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Make unknownCaller the caller in this test. + changePrank({ msgSender: unknownCaller }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodSender), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } + + function test_WithdrawHooks_SenderHook_CallerApprovedOperator() + external + givenSenderContract + givenSameSenderAndRecipient + { + // Create the stream with recipient which is same as the sender contract. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodSender) }); + lockup.approve({ to: users.operator, tokenId: streamId }); + + // Make the operator the caller in this test. + changePrank({ msgSender: users.operator }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodSender), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } + + function test_WithdrawHooks_SenderHook_CallerSender() external givenSenderContract givenSameSenderAndRecipient { + // Create the stream with the sender as the recipient. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodSender) }); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 0 calls to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodSender), withdrawAmount) + ), + count: 0 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } +} diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree new file mode 100644 index 000000000..79a896aa2 --- /dev/null +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree @@ -0,0 +1,21 @@ +withdrawHooks.t.sol +├── given the recipient is different than the sender +│ ├── when the caller is unknown +│ │ ├── it should make one hook call to the sender +│ │ └── it should make one hook call to the recipient +│ ├── when the caller is an approved third party +│ │ ├── it should make one hook call to the sender +│ │ └── it should make one hook call to the recipient +│ ├── when the caller is the sender +│ │ ├── it should not make any hook call to the sender +│ │ └── it should make one hook call to the recipient +│ └── when the caller is the recipient +│ ├── it should make one hook call to the sender +│ └── it should not make any hook call to the recipient +└── given the recipient is same as the sender + ├── when the caller is unknown + │ └── it should make one hook call to the sender + ├── when the caller is an approved third party + │ └── it should make one hook call to the sender + └── when the caller is the sender + └── it should not make any hook call to the sender diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 9e4b9002e..a5247649f 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -16,10 +16,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr Withdraw_Integration_Shared_Test.setUp(); } - /*////////////////////////////////////////////////////////////////////////// - TESTS - //////////////////////////////////////////////////////////////////////////*/ - function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = @@ -197,10 +193,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(defaultStreamId, users.sender); } - modifier givenSenderContract() { - _; - } - function test_Withdraw_SenderDoesNotImplementHook() external whenNotDelegateCalled @@ -316,7 +308,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(streamId, address(goodSender)); } - function test_Withdraw_CallerUnknownAddress() + function test_Withdraw_CallerUnknown() external whenNotDelegateCalled givenNotNull @@ -459,10 +451,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerSender(defaultStreamId, users.recipient); } - modifier givenRecipientContract() { - _; - } - function test_Withdraw_RecipientDoesNotImplementHook() external whenNotDelegateCalled diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index b67bf3aa4..08ee66844 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -147,4 +147,19 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh params.totalAmount = totalAmount; streamId = lockupDynamic.createWithTimestamps(params); } + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + override + returns (uint256 streamId) + { + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + params.recipient = recipient; + streamId = lockupDynamic.createWithTimestamps(params); + } } diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 1fe86adbf..eed455052 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -113,4 +113,19 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha params.totalAmount = totalAmount; streamId = lockupLinear.createWithTimestamps(params); } + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + override + returns (uint256 streamId) + { + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + params.recipient = recipient; + streamId = lockupLinear.createWithTimestamps(params); + } } diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 8fd00072c..9864d3f26 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -50,6 +50,11 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal virtual returns (uint256 streamId); + /// @dev Creates the default stream with recipient as the sender. + function createDefaultStreamToSender(address sender) internal virtual returns (uint256 streamId) { + return createDefaultStreamWithUsers(sender, sender); + } + /// @dev Creates the default stream with the provided address. function createDefaultStreamWithAsset(IERC20 asset) internal virtual returns (uint256 streamId); @@ -70,4 +75,13 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the provided total amount. function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal virtual returns (uint256 streamId); + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + virtual + returns (uint256 streamId); } diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 69fc8cb11..86a1c25d5 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -51,4 +51,12 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ modifier whenStreamHasNotBeenCanceled() { _; } + + modifier givenSenderContract() { + _; + } + + modifier givenRecipientContract() { + _; + } } From 66f5c0f3e3e167a983698e1cd3e9a53d6fd0c049 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 21 Feb 2024 13:43:07 +0200 Subject: [PATCH 048/132] test: update Precompiles bytecode --- test/utils/Precompiles.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 45141e818..a5246bf4c 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -27,11 +27,11 @@ contract Precompiles { bytes public constant BYTECODE_COMPTROLLER = hex"60803461009857601f6102d538819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361022190816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816375829def1461014c57508063b5b3ca2c146100ac578063dcf844a7146100765763f851a4401461004e57600080fd5b346100725781600319360112610072576001600160a01b0360209254169051908152f35b5080fd5b503461007257602036600319011261007257806020926001600160a01b0361009c6101f9565b1681526001845220549051908152f35b50346100725780600319360112610072576100c56101f9565b602435906001600160a01b0390818554163381036101245750907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526001602052808520928084549455815193845260208401523392a380f35b84516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b83903461007257602036600319011261007257600435906001600160a01b03908183168093036101f55783549182163381036101d25750507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6331b339a960e21b82526001600160a01b03166004820152336024820152604490fd5b8380fd5b600435906001600160a01b038216820361020f57565b600080fdfea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0346200046e57601f62005e5d38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a05260016009556040516159c9908162000494823960805181613873015260a051818181610d2101526139940152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126815750806306fdde03146125bc578063081812fc1461259e578063095ea7b31461240a5780631400ecec146123655780631c1cdd4c146122ff5780631e99d569146122e157806323b872dd146122b857806331df3d48146121b557806339a73c031461217257806340e58ee514611f1e578063425d30dd14611f0057806342842e0e14611eb057806342966c6814611d205780634426757014611cf95780634857501f14611c835780634869e12d14611c475780634cc55e1114611b4c57806354c02292146118c75780635fe3b567146118a05780636352211e146118825780636d0cee751461182a57806370a082311461178057806375829def146116ee5780637cad6cd11461161c5780637de6b1db1461140c5780638659c27014611103578063894e9a0d14610e965780638bad38dd14610e1a5780638f69b99314610d975780639067b67714610d445780639188ec8414610d0957806395d89b4114610bf9578063a22cb46514610b28578063a6202bf214610a1f578063a80fc071146109ca578063ad35efd414610967578063b256456914610949578063b637b865146108e9578063b88d4fde14610860578063b8a3be6614610829578063b971302a146107fa578063bc063e1a146107d7578063bc2be1be14610784578063c156a11d146106cc578063c87b56dd14610599578063cc364f48146104ff578063d4dbd20b146104aa578063d511609f1461045b578063d975dfed1461040e578063e985e9c5146103b7578063ea5ead1914610389578063eac8f5b81461031d578063f590c176146102f5578063f851a440146102ce5763fdd46d601461028757600080fd5b346102c95760603660031901126102c9576102a06127ae565b6044356001600160801b03811681036102c9576102c7916102bf613869565b600435613203565b005b600080fd5b346102c95760003660031901126102c95760206001600160a01b0360005416604051908152f35b346102c95760203660031901126102c9576020610313600435612e30565b6040519015158152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160a01b0360016040600020015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b346102c95760403660031901126102c9576102c76004356103a86127ae565b6103b18261433a565b91612e61565b346102c95760403660031901126102c9576103d0612798565b6103d86127ae565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761044a60209161433a565b6001600160801b0360405191168152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602060026040600020015460801c604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160801b0360036040600020015416604051908152f35b346102c95760203660031901126102c95760043560006020604051610523816128e8565b828152015280600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526040806000205464ffffffffff825191610566836128e8565b818160a01c16835260c81c166020820152610597825180926020908164ffffffffff91828151168552015116910152565bf35b346102c9576020806003193601126102c957600435906105d76105d28360005260056020526001600160a01b0360406000205416151590565b612bd9565b60006001600160a01b03600a5416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156106c057600092610647575b50610643604051928284938452830190612773565b0390f35b9091503d806000833e61065a8183612935565b81019082818303126102c95780519067ffffffffffffffff82116102c9570181601f820112156102c957805161068f81612957565b9261069d6040519485612935565b8184528482840101116102c9576106b991848085019101612750565b908261062e565b6040513d6000823e3d90fd5b346102c95760403660031901126102c9576004356106e86127ae565b906106f1613869565b80600052600b60205260ff60016040600020015460a81c1615610372578060005260056020526001600160a01b036040600020541691823303610761576102c79261073b8361433a565b6001600160801b038116610750575b506136ce565b61075b908285612e61565b8461074a565b60405163216caf0d60e01b815260048101839052336024820152604490fd5b0390fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102c95760003660031901126102c957602060405167016345785d8a00008152f35b346102c95760203660031901126102c9576020610818600435612df9565b6001600160a01b0360405191168152f35b346102c95760203660031901126102c957600435600052600b602052602060ff60016040600020015460a81c166040519015158152f35b346102c95760803660031901126102c957610879612798565b6108816127ae565b6064359167ffffffffffffffff83116102c957366023840112156102c9578260040135916108ae83612957565b926108bc6040519485612935565b80845236602482870101116102c95760208160009260246102c79801838801378501015260443591612d63565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526106436109356004604060002001612c9c565b60405191829160208352602083019061283e565b346102c95760203660031901126102c9576020610313600435612d2c565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c1615610372576109a190613568565b60405160058210156109b4576020918152f35b634e487b7160e01b600052602160045260246000fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260206001600160801b0360026040600020015416604051908152f35b346102c95760203660031901126102c957610a38612798565b6001600160a01b038060005416338103610aff57508116908160005260026020526001600160801b0360406000205416908115610ace5781610aa09184600052600260205260406000206fffffffffffffffffffffffffffffffff19815416905533906142d2565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b346102c95760403660031901126102c957610b41612798565b602435908115158092036102c9576001600160a01b031690813314610bb557336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b346102c95760003660031901126102c95760405160006004549060018260011c9160018416918215610cff575b6020948585108414610ce9578587948686529182600014610cc9575050600114610c6c575b50610c5892500383612935565b610643604051928284938452830190612773565b84915060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610cb1575050610c58935082010185610c4b565b80548389018501528794508693909201918101610c9a565b60ff191685820152610c5895151560051b8501019250879150610c4b9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610c26565b346102c95760003660031901126102c95760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c161561037257610dd190613568565b6005811015806109b45760028214908115610e0d575b8115610dfb575b6020826040519015158152f35b90506109b45760046020911482610dee565b5050600381146000610de7565b346102c95760203660031901126102c9576004356001600160a01b03908181168091036102c9578160005416338103610aff575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b346102c95760203660031901126102c9576060610140604051610eb881612918565b60008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152610efc612c49565b6101208201520152600435600052600b60205260ff60016040600020015460a81c16156110eb57600435600052600b6020526040600020610fdf600460405192610f4584612918565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c161515610100850152610fd360028201612c68565b61012085015201612c9c565b610140820152610ff0600435613568565b9060058210156109b457600261014092146110df575b610643604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e0810151151561010085015261010081015115156101208501526110cb61012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c083019061283e565b60006060820152611006565b602460405162b8e7e760e51b81526004356004820152fd5b346102c9576020806003193601126102c95760043567ffffffffffffffff81116102c95761113590369060040161280d565b9061113e613869565b6000915b80831061114b57005b611156838284612b7e565b3592611160613869565b61116984612b47565b156111865760248460405190634a5541ef60e01b82526004820152fd5b61119284929394612e30565b6113f4576111b682600052600b6020526001600160a01b0360406000205416331490565b15610761576111c4826134fd565b82600052600b8087526111dd6002604060002001612c68565b906001600160801b03928383511684821610156113dc578560005281895260ff60406000205460f01c16156113c4579061122d82858b61122361131296838951166129c4565b96015116906129c4565b86600052818a52896040600020947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841617885560038986169889156113aa575b0198811698896fffffffffffffffffffffffffffffffff198254161790558a6001600160a01b038094169788946005875280604060002054169889975260016040600020015416966112e88c878a6142d2565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b611355575b5050505060019150019190611142565b803b156102c95760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161139b575b808080611345565b6113a490612904565b85611393565b60018101600160a01b60ff60a01b19825416179055611295565b602486604051906339c6dc7360e21b82526004820152fd5b602486604051906322cad1af60e11b82526004820152fd5b6024826040519063fe19f19f60e01b82526004820152fd5b346102c9576020806003193601126102c9576004359061142a613869565b81600052600b815260ff60016040600020015460a81c16156116055761144f82613568565b60058110156109b457600481036114785760248360405190634a5541ef60e01b82526004820152fd5b60038103611498576024836040519063fe19f19f60e01b82526004820152fd5b6002146115ed576114bf82600052600b6020526001600160a01b0360406000205416331490565b156107615781600052600b815260ff60406000205460f01c16156115d55781600052600b8152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600582526001600160a01b036040600020541692833b611566575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b156102c957600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af11561153a576115cf90612904565b8361153a565b602482604051906339c6dc7360e21b82526004820152fd5b602482604051906322cad1af60e11b82526004820152fd5b6024826040519062b8e7e760e51b82526004820152fd5b346102c95760203660031901126102c9576004356001600160a01b03908181168091036102c9578160005416338103610aff5750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116116d85760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b346102c95760203660031901126102c957611707612798565b6000546001600160a01b0380821692338403611759576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b346102c95760203660031901126102c9576001600160a01b036117a1612798565b1680156117c05760005260066020526020604060002054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102c95760203660031901126102c9576004356118616105d28260005260056020526001600160a01b0360406000205416151590565b600052600560205260206001600160a01b0360406000205416604051908152f35b346102c95760203660031901126102c9576020610818600435612c24565b346102c95760003660031901126102c95760206001600160a01b0360015416604051908152f35b346102c957602060031981813601126102c95760043567ffffffffffffffff918282116102c957610120823603918201126102c957611904613869565b60c482013590602219018112156102c95781016004810135908382116102c95760240160608202360381136102c95761193e913691612a78565b9182519161194b83612a60565b926119596040519485612935565b808452601f1961196882612a60565b018660005b828110611b365750505064ffffffffff90814216936001600160801b039687611995826138c5565b515116828a6119a3846138c5565b51015116858060406119b4866138c5565b5101511689011690604051926119c9846128cc565b83528b83015260408201526119dd886138c5565b526119e7876138c5565b506001938760015b8a8c878310611ab55790838b8b611a0881600401612bb8565b92611a1560248301612bb8565b92611a2260448401612ba4565b946064840135946001600160a01b03958681168091036102c957611aad98611a6d98611aa298611a5460848a01612bcc565b9481611a6260a48c01612bcc565b976040519d8e6128af565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612b18565b6101008201526138e6565b604051908152f35b889385806040611ae98b86611ad98a8e9a611ad0828d6138d2565b5151169a6138d2565b51015116946000198901906138d2565b51015116816040611afa888c6138d2565b5101511601169160405193611b0e856128cc565b84528301526040820152611b22828c6138d2565b52611b2d818b6138d2565b500188906119ef565b611b3e612c49565b82828901015201879061196d565b346102c95760403660031901126102c95767ffffffffffffffff6004358181116102c957611b7e90369060040161280d565b916024359081116102c957611b9790369060040161280d565b9091611ba1613869565b818403611c105760005b848110611bb457005b80611c0a611bc56001938886612b7e565b35611bd1838987612b7e565b3560005260056020526001600160a01b0360406000205416611bfc611bf785898b612b7e565b612ba4565b91611c05613869565b613203565b01611bab565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761044a602091614257565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c1615610372576000611cbf82613568565b60058110156109b457600203611cdd575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611cd0565b346102c95760003660031901126102c95760206001600160a01b03600a5416604051908152f35b346102c95760203660031901126102c957600435611d3c613869565b611d4581612b47565b15611e7f57611d53816141ee565b15611e5f57611d6181612c24565b611d6a82612d2c565b159081611e56575b81611e43575b50611e2b57602081611daa7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793612c24565b9080600052600783526001600160a01b036040600020926001600160a01b031993848154169055169182600052600684526040600020600019815401905581600052600584526040600020908154169055806000604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a1005b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b03915016151582611d78565b60009150611d72565b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b346102c957611ebe366127d8565b60405191602083019383851067ffffffffffffffff861117611eea576102c79460405260008452612d63565b634e487b7160e01b600052604160045260246000fd5b346102c95760203660031901126102c9576020610313600435612b47565b346102c9576020806003193601126102c95760043590611f3c613869565b611f4582612b47565b15611f625760248260405190634a5541ef60e01b82526004820152fd5b611f6b82612e30565b6113f457611f8f82600052600b6020526001600160a01b0360406000205416331490565b1561076157611f9d826134fd565b9180600052600b8252611fb66002604060002001612c68565b906001600160801b03938483511685821610156115ed5781600052600b845260ff60406000205460f01c16156115d557808585611ff961200394838851166129c4565b95015116906129c4565b9080600052600b84527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7604060002094855494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161787556003888616978815612158575b0197811697886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169560058352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508260406000205416978893600b875260016040600020015416946120e18d85886142d2565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b61211357005b813b156102c95760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161214f57005b6102c790612904565b60018101600160a01b60ff60a01b1982541617905561206c565b346102c95760203660031901126102c9576001600160a01b03612193612798565b16600052600260205260206001600160801b0360406000205416604051908152f35b346102c9576003196020368201126102c95760043567ffffffffffffffff918282116102c9576101409082360301126102c9576121f0613869565b604051916121fd836128af565b612209826004016127c4565b8352612217602483016127c4565b602084015261222860448301612973565b6040840152612239606483016127c4565b606084015261224a608483016128a2565b608084015261225b60a483016128a2565b60a084015261226c60c48301612a4e565b60c084015260e48201359081116102c957810191366023840112156102c957611aa2611aad926122a86020953690602460048201359101612a78565b60e0840152610104369101612b18565b346102c9576102c76122c9366127d8565b916122dc6122d784336135ef565b6129dd565b6136ce565b346102c95760003660031901126102c9576020600954604051908152f35b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725761233990613568565b60058110156109b457806020911590811561235a575b506040519015158152f35b60019150148261234f565b346102c95760203660031901126102c95760043580600052600b60205260ff60016040600020015460a81c16156103725760209060009080600052600b8352604060002060ff815460f01c16806123f8575b6123cf575b50506001600160801b0360405191168152f35b6123f192506001600160801b0360026123eb92015416916134fd565b906129c4565b82806123bc565b5060ff600182015460a01c16156123b7565b346102c95760403660031901126102c957612423612798565b602435906001600160a01b03808061243a85612c24565b169216918083146125345780331490811561250f575b50156124a5578260005260076020526040600020826001600160a01b031982541617905561247d83612c24565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4005b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050600052600860205260406000203360005260205260ff6040600020541684612450565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b346102c95760203660031901126102c9576020610818600435612987565b346102c95760003660031901126102c95760405160006003549060018260011c9160018416918215612677575b6020948585108414610ce9578587948686529182600014610cc957505060011461261a5750610c5892500383612935565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b85831061265f575050610c58935082010185610c4b565b80548389018501528794508693909201918101612648565b92607f16926125e9565b346102c95760203660031901126102c957600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102c957817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612726575b81156126fc575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836126f5565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126ee565b60005b8381106127635750506000910152565b8181015183820152602001612753565b9060209161278c81518092818552858086019101612750565b601f01601f1916010190565b600435906001600160a01b03821682036102c957565b602435906001600160a01b03821682036102c957565b35906001600160a01b03821682036102c957565b60609060031901126102c9576001600160a01b039060043582811681036102c9579160243590811681036102c9579060443590565b9181601f840112156102c95782359167ffffffffffffffff83116102c9576020808501948460051b0101116102c957565b90815180825260208080930193019160005b82811061285e575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612850565b359081151582036102c957565b610120810190811067ffffffffffffffff821117611eea57604052565b6060810190811067ffffffffffffffff821117611eea57604052565b6040810190811067ffffffffffffffff821117611eea57604052565b67ffffffffffffffff8111611eea57604052565b610160810190811067ffffffffffffffff821117611eea57604052565b90601f8019910116810190811067ffffffffffffffff821117611eea57604052565b67ffffffffffffffff8111611eea57601f01601f191660200190565b35906001600160801b03821682036102c957565b6129aa6105d28260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116116d857565b156129e457565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b359064ffffffffff821682036102c957565b67ffffffffffffffff8111611eea5760051b60200190565b929192612a8482612a60565b604094612a946040519283612935565b819584835260208093019160608096028501948186116102c957925b858410612ac05750505050505050565b86848303126102c957825190612ad5826128cc565b612ade85612973565b8252858501359067ffffffffffffffff821682036102c957828792838b950152612b09868801612a4e565b86820152815201930192612ab0565b91908260409103126102c957604051612b30816128e8565b6020808294612b3e816127c4565b84520135910152565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260ff60016040600020015460a01c1690565b9190811015612b8e5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102c95790565b356001600160a01b03811681036102c95790565b3580151581036102c95790565b15612be057565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b0360406000205416612c46811515612bd9565b90565b60405190612c56826128cc565b60006040838281528260208201520152565b90604051612c75816128cc565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612ca881612a60565b92604093612cb96040519182612935565b82815280946020809201926000526020600020906000935b858510612ce057505050505050565b60018481928451612cf0816128cc565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612cd1565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260ff60016040600020015460b01c1690565b90612d87939291612d776122d784336135ef565b612d828383836136ce565b61496e565b15612d8e57565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460a81c161561037257600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460a81c161561037257600052600b60205260406000205460f81c90565b929192612e6c613869565b600093612e7882612b47565b6131eb576001600160a01b03928381169182156131c1576001600160801b03948582169586156131a9578589526020966005885260409583878c205416928382141580613199575b61315d57612ee88960028a8f600b8f612ed886614257565b9583525220015460801c906129c4565b818116841161312c575090887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b878f8c6001918c9b9a9998612f79612f47612f308a612df9565b9e8a8552600b89526002868620015460801c614362565b898452600b885260028585200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155612c68565b90612f948188840151169282868183511692015116906129c4565b1611156130fe575b868152600b85522001541694612fb3818c886142d2565b8b51908152a480331415806130f4575b61308e575b50811690813314159081613083575b5061300b575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b1561307f578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613067575b8080612fdd565b6130718691612904565b61307b5784613060565b8480fd5b8280fd5b90503b151538612fd7565b89813b156130f1578651636fd110e960e01b8152600481018990523360248201526001600160a01b03871660448201526001600160801b0386166064820152918290608490829084905af115612fc8576130ea90999199612904565b9738612fc8565b80fd5b50803b1515612fc3565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612f9c565b885163287ecaef60e21b8152600481018b90526001600160801b038881166024830152919091166044820152606490fd5b606489838a51917fb34359d300000000000000000000000000000000000000000000000000000000835260048301523360248301526044820152fd5b506131a3896141ee565b15612ec0565b6024866040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248260405190634a5541ef60e01b82526004820152fd5b9291909261321081612b47565b6134e5576001600160a01b03918285169081156131c1576001600160801b03958682169485156134cd576000978589526020966005885260409583878c2054169283821415806134bd575b61315d576132688961433a565b818116841161348c575090887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8b878f8c6001918d9c9b9a99986132c8612f476132b18a612df9565b9f8a8552600b89526002868620015460801c614362565b906132e38188840151169282868183511692015116906129c4565b16111561345e575b868152600b85522001541694613302818a886142d2565b8b51908152a48033141580613454575b6133f5575b508216918233141590816133ea575b50613359575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156133e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16133d7575b859481612fdd565b6133e090612904565b386133cf565b8780fd5b90503b151538613326565b89813b156130f1578651636fd110e960e01b8152600481018990523360248201526001600160a01b03851660448201526001600160801b0387166064820152918290608490829084905af1156133175761344e90612904565b38613317565b50803b1515613312565b868152600b8552818120838101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556132eb565b885163287ecaef60e21b8152600481018b90526001600160801b038981166024830152919091166044820152606490fd5b506134c7896141ee565b1561325b565b6024856040519063d2aabcd960e01b82526004820152fd5b60249060405190634a5541ef60e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c16101561355e5760c81c16111561354c57600401546001101561354357612c4690614451565b612c469061437d565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c1660001461358f575050600490565b805460f81c6135e8575460a01c64ffffffffff1642106135e2576135b2816134fd565b90600052600b6020526001600160801b0380600260406000200154169116106000146135dd57600190565b600290565b50600090565b5050600390565b906001600160a01b03808061360384612c24565b16931691838314938415613636575b508315613620575b50505090565b61362c91929350612987565b161438808061361a565b909350600052600860205260406000208260005260205260ff604060002054169238613612565b1561366457565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b906136f792916136dd83612c24565b916001600160a01b0394859384809416968791161461365d565b16908115806138005761370984612d2c565b1590816137f7575b50806137ee575b6137d657918084926137587ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79660209661375185612c24565b161461365d565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b50831515613718565b90501538613711565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361389b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612b8e5760200190565b8051821015612b8e5760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106c0576000906141ba575b61396891506001600160801b0360408501511690602061010086015101519161463c565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141905781518015614166577f00000000000000000000000000000000000000000000000000000000000000008111614135575064ffffffffff60406139cb846138c5565b510151168110156140de5750600090819082815184905b80821061404d575050505064ffffffffff421664ffffffffff821681101561400d5750506001600160801b0316808203613fd65750506009549283600052600b6020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606083015116600184015490750100000000000000000000000000000000000000000060808501511515928654927fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b038451169160e0850151926040613afc8551956000198701906138d2565b510151927fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff000000000000000000000000000000000000000060c08b015160a01b169660c81b169460f01b16911617171717845560005b818110613f07575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036020830151168015613ec357613c43613c3d8760005260056020526001600160a01b0360406000205416151590565b1561477b565b613c4c86612d2c565b1580613eba575b80613eb2575b613e9a5760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613ca4613c3d8960005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905587600052600582526040600020816001600160a01b0319825416179055876040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4878152a1613d346001600160a01b036060840151166001600160801b038084511681602086015116011690309033906147c6565b6001600160801b0360408201511680613e6a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb613e276001600160a01b03845116926001600160a01b03602086015116946001600160a01b0360608201511696613e5f613e3f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613dd38c6128e8565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e088015286019061283e565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b613e94906001600160a01b036060850151166001600160a01b0361010086015151169033906147c6565b38613d48565b60248660405190630da9b01360e01b82526004820152fd5b506000613c59565b50801515613c53565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b613f158160e08601516138d2565b519060048601549168010000000000000000831015611eea5760018301806004890155831015612b8e5760019260048801600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613b98565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614071906001600160801b0361406885886138d2565b51511690614362565b9364ffffffffff80604061408586856138d2565b510151169416808511156140a1575060018493019092916139e2565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff60406140ef846138c5565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116141e6575b816141d460209383612935565b810103126102c9576139689051613944565b3d91506141c7565b60009080825260056020526001600160a01b038060408420541692833314938415614233575b5050821561422157505090565b90915061422e3392612987565b161490565b60ff9294509060409181526008602052818120338252602052205416913880614214565b80600052600b6020526142706002604060002001612c68565b81600052600b602052604060002060ff600182015460a01c166000146142a357506001600160801b039150602001511690565b5460f81c6142b55750612c46906134fd565b612c4691506001600160801b0360408183511692015116906129c4565b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff841117611eea5761433892604052614831565b565b612c469061434781614257565b90600052600b60205260026040600020015460801c906129c4565b9190916001600160801b03808094169116019182116116d857565b64ffffffffff6143b2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614b01565b91808252600b6020526004604083200180541561443d5790829167ffffffffffffffff935261440f6020832054828452600b60205261440a6001600160801b03968760026040882001541696879360801c1690614bf1565b614c5f565b92831361442557505061442190614d49565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff90814216906000908152600b60205260409081812082519361447885612918565b8154956001600160a01b039182881687526020870197828160a01c168952828160c81c168789015260ff8160f01c161515606089015260f81c1515608088015260ff600193600186015490811660a08a0152818160a01c16151560c08a0152818160a81c16151560e08a015260b01c161515610100880152610140614513600461450460028801612c68565b966101208b0197885201612c9c565b9701918783528087614525889a6138c5565b5101511693828288965b16106146045750916145b961440a928488816145be98976001600160801b039e8f61455b8b8a516138d2565b5151169d8a8f9b602061457867ffffffffffffffff928d516138d2565b5101511699848361458a8484516138d2565b51015116965081156145f8576145a8929350519060001901906138d2565b5101511680925b0316920316614b01565b614bf1565b9283136145d75750506145d18391614d49565b16011690565b5160200151929392831692841683101591506145f39050575090565b905090565b505050511680926145af565b8094986001600160801b03908161461c8c88516138d2565b51511601169801938282808a6146338989516138d2565b5101511661452f565b909291614647612c49565b936001600160801b03928381169182156147535767016345785d8a000080821161471c578085116146e5575061469185614682819386615875565b16946020890195865284615875565b1691846146a8604089019480865282875116614362565b1610156146cf576146c18491826146ca955116906129c4565b915116906129c4565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614766816128cc565b60008152600060208201526000604082015290565b1561478257565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611eea57614338926040525b6001600160a01b03169061489160405161484a816128e8565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af161488b61493e565b91615924565b805191821591848315614916575b5050509050156148ac5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b91938180945001031261493a578201519081151582036130f157508038808461489f565b5080fd5b3d15614969573d9061494f82612957565b9161495d6040519384612935565b82523d6000602084013e565b606090565b9290803b15614af8576149d8916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c86523360048701521660248501526044840152608060648401526084830190612773565b03916000968791165af190829082614a97575b5050614a71576149f961493e565b80519081614a6c5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d602011614af0575b81614ab460209383612935565b8101031261493a5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036130f157509038806149eb565b3d9150614aa7565b50505050600190565b600160ff1b808214908115614be7575b50614bbd576000811215614bb457614b3a816000035b6000841215614bad578360000390614d85565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614b765760001991181315614b705790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614d85565b614b3a81614b27565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614b11565b80614c0c5750614c0757670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614c59575080614c31575050670de0b6b3a764000090565b670de0b6b3a76400008114614c5557614c509061440a612c4693614e7f565b614fc1565b5090565b91505090565b600160ff1b808214908115614d3f575b50614d15576000811215614d0c57614c98816000035b6000841215614d05578360000390615875565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614cce5760001991181315614b705790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615875565b614c9881614c85565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c6f565b60008112614d545790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614e415782851015614e0557908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614e4f570490565b634e487b7160e01b600052601260045260246000fd5b8015614e4f576ec097ce7bc90715b34b9f10000000000590565b80600080831315614f9057670de0b6b3a764000092838112614f6d57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614f6157506706f05b59d3b20000905b848213614f355750505050500290565b808391020590671bc16d674ec80000821215614f54575b831d90614f25565b8091950194831d90614f4c565b93505093925050020290565b6000199392508015614e4f576ec097ce7bc90715b34b9f10000000000591614ea0565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614ff05768033dd1780914b971141981126135e257614fe790600003614fc1565b612c4690614e65565b680a688906bd8affffff811361584457670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615727575b66ff000000000000831661561f575b65ff0000000000831661551f575b64ff000000008316615427575b63ff0000008316615337575b62ff0000831661524f575b61ff00831661516f575b60ff8316615098575b02911c60bf031c90565b6080831661515d575b83831661514b575b60208316615139575b60108316615127575b60088316615115575b60048316615103575b600283166150f1575b600183161561508e576801000000000000000102831c61508e565b6801000000000000000102831c6150d6565b6801000000000000000302831c6150cd565b6801000000000000000602831c6150c4565b6801000000000000000b02831c6150bb565b6801000000000000001602831c6150b2565b6801000000000000002c02831c6150a9565b6801000000000000005902831c6150a1565b618000831661523d575b614000831661522b575b6120008316615219575b6110008316615207575b61080083166151f5575b61040083166151e3575b61020083166151d1575b61010083161561508557680100000000000000b102831c615085565b6801000000000000016302831c6151b5565b680100000000000002c602831c6151ab565b6801000000000000058c02831c6151a1565b68010000000000000b1702831c615197565b6801000000000000162e02831c61518d565b68010000000000002c5d02831c615183565b680100000000000058b902831c615179565b628000008316615325575b624000008316615313575b622000008316615301575b6210000083166152ef575b6208000083166152dd575b6204000083166152cb575b6202000083166152b9575b6201000083161561507b576801000000000000b17202831c61507b565b680100000000000162e402831c61529c565b6801000000000002c5c802831c615291565b68010000000000058b9102831c615286565b680100000000000b172102831c61527b565b68010000000000162e4302831c615270565b680100000000002c5c8602831c615265565b6801000000000058b90c02831c61525a565b63800000008316615415575b63400000008316615403575b632000000083166153f1575b631000000083166153df575b630800000083166153cd575b630400000083166153bb575b630200000083166153a9575b63010000008316156150705768010000000000b1721802831c615070565b6801000000000162e43002831c61538b565b68010000000002c5c86002831c61537f565b680100000000058b90c002831c615373565b6801000000000b17217f02831c615367565b680100000000162e42ff02831c61535b565b6801000000002c5c85fe02831c61534f565b68010000000058b90bfc02831c615343565b648000000000831661550d575b64400000000083166154fb575b64200000000083166154e9575b64100000000083166154d7575b64080000000083166154c5575b64040000000083166154b3575b64020000000083166154a1575b64010000000083161561506457680100000000b17217f802831c615064565b68010000000162e42ff102831c615482565b680100000002c5c85fe302831c615475565b6801000000058b90bfce02831c615468565b68010000000b17217fbb02831c61545b565b6801000000162e42fff002831c61544e565b68010000002c5c8601cc02831c615441565b680100000058b90c0b4902831c615434565b65800000000000831661560d575b6540000000000083166155fb575b6520000000000083166155e9575b6510000000000083166155d7575b6508000000000083166155c5575b6504000000000083166155b3575b6502000000000083166155a1575b65010000000000831615615057576801000000b17218355102831c615057565b680100000162e430e5a202831c615581565b6801000002c5c863b73f02831c615573565b68010000058b90cf1e6e02831c615565565b680100000b1721bcfc9a02831c615557565b68010000162e43f4f83102831c615549565b680100002c5c89d5ec6d02831c61553b565b6801000058b91b5bc9ae02831c61552d565b66800000000000008316615715575b66400000000000008316615703575b662000000000000083166156f1575b661000000000000083166156df575b660800000000000083166156cd575b660400000000000083166156bb575b660200000000000083166156a9575b66010000000000008316156150495768010000b17255775c0402831c615049565b6801000162e525ee054702831c615688565b68010002c5cc37da949202831c615679565b680100058ba01fb9f96d02831c61566a565b6801000b175effdc76ba02831c61565b565b680100162f3904051fa102831c61564c565b6801002c605e2e8cec5002831c61563d565b68010058c86da1c09ea202831c61562e565b6780000000000000008316615825575b6740000000000000008316615813575b6720000000000000008316615801575b67100000000000000083166157ef575b67080000000000000083166157dd575b67040000000000000083166157cb575b67020000000000000083166157b9575b67010000000000000083161561503a57680100b1afa5abcbed6102831c61503a565b68010163da9fb33356d802831c615797565b680102c9a3e778060ee702831c615787565b6801059b0d31585743ae02831c615777565b68010b5586cf9890f62a02831c615767565b6801172b83c7d517adce02831c615757565b6801306fe0a31b7152df02831c615747565b5077b504f333f9de648480000000000000000000000000000000615737565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461591357670de0b6b3a764000090818310156158dc57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b919290156159855750815115615938575090565b3b156159415790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156159985750805190602001fd5b6107809060405191829162461bcd60e51b835260206004840152602483019061277356fea164736f6c6343000817000a"; + hex"60c0346200046e57601f62005f8a38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615af6908162000494823960805181613d2b015260a051818181610e350152613e4c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a714612a185750806306fdde031461291b578063081812fc146128fd578063095ea7b3146127f65780631400ecec146127505780631c1cdd4c146126ea5780631e99d569146126cc57806323b872dd146126b557806331df3d48146125b257806339a73c031461256f57806340e58ee514612277578063425d30dd1461222157806342842e0e146121d057806342966c6814611fbd5780634426757014611f965780634857501f14611f1c5780634869e12d14611edf5780634cc55e1114611de457806354c0229214611b485780635fe3b56714611b215780636352211e14611af25780636d0cee7514611af257806370a0823114611a7e57806375829def146119e45780637cad6cd1146118e65780637de6b1db146116c95780638659c27014611379578063894e9a0d14610ff35780638bad38dd14610f485780638f69b99314610ead5780639067b67714610e585780639188ec8414610e1d57806395d89b4114610d09578063a22cb46514610c4b578063a6202bf214610b43578063a80fc07114610aec578063ad35efd414610a73578063b256456914610a1d578063b637b865146109be578063b88d4fde14610935578063b8a3be66146108ff578063b971302a146108ab578063bc063e1a14610888578063bc2be1be14610833578063c156a11d146106dd578063c87b56dd146105c9578063cc364f481461052d578063d4dbd20b146104d6578063d511609f14610485578063d975dfed14610437578063e985e9c5146103e0578063ea5ead19146103b2578063eac8f5b81461035b578063f590c176146102f6578063f851a440146102cf5763fdd46d601461028957600080fd5b346102ca5760603660031901126102ca576102a2612b44565b604435906001600160801b03821682036102ca576102c8926102c2613d21565b3561371c565b005b600080fd5b346102ca5760003660031901126102ca5760206001600160a01b0360005416604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360016040600020015416604051908152f35b50346102ca5760403660031901126102ca576102c890356103d1612b44565b6103da8261467a565b9161337a565b346102ca5760403660031901126102ca576103f9612b2e565b610401612b44565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760206104748361467a565b6001600160801b0360405191168152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060026040600020015460801c604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360036040600020015416604051908152f35b50346102ca5760203660031901126102ca578035906000602060405161055281612c94565b828152015281600052600b60205260ff60016040600020015460a81c16156103465750600052600b6020526040806000205464ffffffffff82519161059683612c94565b818160a01c16835260c81c1660208201526105c7825180926020908164ffffffffff91828151168552015116910152565bf35b50346102ca576020806003193601126102ca57600082356105e981613aa2565b5060446001600160a01b03600a54169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106d157600092610658575b50610654604051928284938452830190612b09565b0390f35b9091503d806000833e61066b8183612ce1565b81019082818303126102ca5780519067ffffffffffffffff82116102ca570181601f820112156102ca5780516106a081612d03565b926106ae6040519485612ce1565b8184528482840101116102ca576106ca91848085019101612ae6565b903861063f565b6040513d6000823e3d90fd5b50346102ca5760403660031901126102ca578035906106fa612b44565b91610703613d21565b80600052600b60205260ff60016040600020015460a81c161561081d578060005260056020526001600160a01b038060406000205416938433036107fa5761074a8361467a565b6001600160801b0381166107e9575b50818116156107d1578261076c91613bdc565b9081168061078b576024848460405191637e27328960e01b8352820152fd5b840361079357005b6107cd916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107f490868561337a565b38610759565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102ca5760003660031901126102ca57602060405167016345785d8a00008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360406000205416604051908152f35b50346102ca5760203660031901126102ca5735600052600b602052602060ff60016040600020015460a81c166040519015158152f35b50346102ca5760803660031901126102ca5761094f612b2e565b610957612b44565b906064359267ffffffffffffffff84116102ca57366023850112156102ca578301359161098383612d03565b926109916040519485612ce1565b80845236602482870101116102ca5760208160009260246102c89801838801378501015260443591613206565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600c602052610654610a096040600020613176565b604051918291602083526020830190612bd4565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460b01c166040519015158152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610aad90613b55565b604051906005811015610ac257602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360026040600020015416604051908152f35b50346102ca5760203660031901126102ca57610b5d612b2e565b906001600160a01b038060005416338103610c1c57508216918260005260026020526001600160801b0360406000205416918215610bec575081610bbe9184600052600260205260406000206001600160801b0319815416905533906145ee565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b60249084604051917f8410168c000000000000000000000000000000000000000000000000000000008352820152fd5b604080516331b339a960e21b81526001600160a01b039092169382019384523360208501529092839250010390fd5b50346102ca5760403660031901126102ca57610c65612b2e565b602435908115158092036102ca576001600160a01b0316918215610cd95750336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760003660031901126102ca576040519060009080549160018360011c9260018516948515610e13575b6020958686108114610dfe57858852879493929187908215610ddc575050600114610d80575b5050610d6c92500383612ce1565b610654604051928284938452830190612b09565b8592506000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610dc4575050610d6c93508201013880610d5e565b80548389018501528794508693909201918101610dac565b9250935050610d6c94915060ff191682840152151560051b8201013880610d5e565b602283634e487b7160e01b6000525260246000fd5b93607f1693610d38565b346102ca5760003660031901126102ca5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610ee790613b55565b9060058210159081610f255760028314918215610f3a575b8215610f13575b6020836040519015158152f35b909150610f2557602091143880610f06565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610eff565b50346102ca5760203660031901126102ca5780356001600160a01b03918282168092036102ca578260005416338103610fc557505060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b604080516331b339a960e21b81526001600160a01b0390921692820192835233602084015290918291010390fd5b50346102ca5760203660031901126102ca57604051610160810181811067ffffffffffffffff821117611364576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e0820152600061010082015261106e613123565b61012082015201528035600052600b60205260ff60016040600020015460a81c161561134c578035600052600b60205260406000209061113e6002604051936110b685612cc4565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613142565b61012083015261114e8135613b55565b60058110156113375760021461132b575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600c602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761131657506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161123990613176565b82820152610654604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130261012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190612bd4565b604190634e487b7160e01b6000525260246000fd5b6000606083015261115f565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b50346102ca57602090816003193601126102ca57803567ffffffffffffffff81116102ca576113ab9036908301612ba3565b90926113b5613d21565b6000915b8083106113c257005b6113cd8382876130c8565b35926113d7613d21565b83600052600b9081845260ff9160019280846040600020015460a81c16156116b357866000528186526040600020818582015460a01c1660001461142c576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c61169c5761145c81600052600b6020526001600160a01b0360406000205416331490565b1561167a5761146a81613add565b92816000528088526114826002604060002001613142565b936001600160801b03938486511685831610156116635783600052828a5260406000205460f01c161561164c5780848a6114c26114cc94838a5116612d57565b9701511690612d57565b9382600052818952886040600020977f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50895497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a16178b5560038882169b8c15611633575b0197851697886001600160801b03198254161790556001600160a01b038099169889936005865281604060002054169788965260406000200154169461157c8985886145ee565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6115df575b50505050600191500191906113b9565b803b156102ca578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611624575b8080806115cf565b61162d90612cb0565b3861161c565b848101600160a01b60ff60a01b19825416179055611535565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b50346102ca57602090816003193601126102ca5780356116e7613d21565b80600052600b835260ff60016040600020015460a81c161561081d5761170c81613b55565b926005841015610ac257838303611734576024838360405191634a5541ef60e01b8352820152fd5b6003840361175357602483836040519163fe19f19f60e01b8352820152fd5b90600284146118cf5761177c81600052600b6020526001600160a01b0360406000205416331490565b156118ad5780600052600b825260ff60406000205460f01c16156118965780600052600b8252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600583526001600160a01b036040600020541693843b611822575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b156102ca578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611887575b806117f6565b61189090612cb0565b83611881565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b50346102ca5760203660031901126102ca5780356001600160a01b03908181168091036102ca5781600054163381036119b85750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101919082116119a3577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576119fe612b2e565b600054906001600160a01b0390818316338103611a5257506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576001600160a01b03611aa0612b2e565b16908115611ac1575060005260066020526020604060002054604051908152f35b6024906000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760203660031901126102ca57611b1060209135613aa2565b6001600160a01b0360405191168152f35b346102ca5760003660031901126102ca5760206001600160a01b0360015416604051908152f35b50346102ca576020906003199082823601126102ca5780359167ffffffffffffffff908184116102ca57610120843603918201126102ca57611b88613d21565b60c484013590602219018112156102ca57830182810135908282116102ca5760240160608202360381136102ca57611bc1913691612ff9565b9283519281611bcf85612fe1565b94611bdd6040519687612ce1565b808652601f19611bec82612fe1565b018860005b828110611dc65750505064ffffffffff90814216956001600160801b039889611c1982613d7d565b515116828c611c2784613d7d565b5101511685806040611c3886613d7d565b510151168b01169060405192611c4d84612c78565b83528d8301526040820152611c618a613d7d565b52611c6b89613d7d565b5060019360015b8c8b8d878410611d3757908c8a611c8a818e01613102565b92611c9760248301613102565b92611ca4604484016130ee565b946064840135946001600160a01b03958681168091036102ca57611d2f98611cef98611d2498611cd660848a01613116565b9481611ce460a48c01613116565b976040519d8e612c45565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613099565b610100820152613d9e565b604051908152f35b8899509084806040611d748a87611d648c9d9e9f9b9c99988b90611d5b828d613d8a565b5151169a613d8a565b5101511694600019890190613d8a565b51015116816040611d85888c613d8a565b5101511601169160405193611d9985612c78565b84528301526040820152611dad828d613d8a565b52611db8818c613d8a565b500190879594939291611c72565b9091929350611dd3613123565b82828a010152019088859392611bf1565b50346102ca5760403660031901126102ca5767ffffffffffffffff9080358281116102ca57611e169036908301612ba3565b926024359081116102ca57611e2e9036908401612ba3565b919092611e39613d21565b828503611ea9575060005b848110611e4d57005b80611ea3611e5e60019388866130c8565b35611e6a8389876130c8565b3560005260056020526001600160a01b0360406000205416611e95611e9085898b6130c8565b6130ee565b91611e9e613d21565b61371c565b01611e44565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657602061047483614b1c565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657600090611f5a83613b55565b906005821015610f255750600203611f7a575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611f6d565b346102ca5760003660031901126102ca5760206001600160a01b03600a5416604051908152f35b50346102ca57602090816003193601126102ca57803591611fdc613d21565b82600052600b815260ff60016040600020015460a81c16156121ba5782600052600b815260ff60016040600020015460a01c161561218a5761201d83614585565b156121665782600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c1615908161215c575b5080612154575b61213d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526005835260406000205416918215928315612102575b856000526005825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a16120ec57005b60249160405191637e27328960e01b8352820152fd5b61212386600052600760205260406000206001600160a01b03198154169055565b80600052600682526040600020600019815401905561209c565b6024838560405191630da9b01360e01b8352820152fd5b50600061205c565b9050151538612055565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b50346102ca576121df36612b6e565b90604051926020840184811067ffffffffffffffff82111761220c576102c8955060405260008452613206565b604186634e487b7160e01b6000525260246000fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460a01c166040519015158152f35b50346102ca57602090816003193601126102ca578035612295613d21565b80600052600b80845260ff60016040600020015460a81c16156125595781600052808452604060002060ff600182015460a01c166000146122e7576024848460405191634a5541ef60e01b8352820152fd5b5460f81c6125425761230f82600052600b6020526001600160a01b0360406000205416331490565b156125205761231d82613add565b92826000528185526123356002604060002001613142565b936001600160801b0390818651168282161015612509578460005283875260ff60406000205460f01c16156124f257866123c482847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a6123ba7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612d57565b9a01511690612d57565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156124d8575b0195811695866001600160801b03198254161790556001600160a01b03809a169a8b91600586528a6124828d604060002054169d8e96895260016040600020015416966124588b878a6145ee565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61249457005b843b156102ca576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16124cf57005b6102c890612cb0565b60018101600160a01b60ff60a01b1982541617905561240a565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b346102ca5760203660031901126102ca576001600160a01b03612590612b2e565b16600052600260205260206001600160801b0360406000205416604051908152f35b50346102ca57600319906020368301126102ca5780359167ffffffffffffffff908184116102ca576101409084360301126102ca576125ef613d21565b604051906125fc82612c45565b612607848401612b5a565b825261261560248501612b5a565b602083015261262660448501612d1f565b604083015261263760648501612b5a565b606083015261264860848501612c38565b608083015261265960a48501612c38565b60a083015261266a60c48501612fcf565b60c083015260e48401359081116102ca57830191366023840112156102ca576020936126a5611d2492611d2f95602436928201359101612ff9565b60e0840152610104369101613099565b346102ca576102c86126c636612b6e565b91612d86565b346102ca5760003660031901126102ca576020600954604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad75761272490613b55565b906005821015610f255760208215838115612745575b506040519015158152f35b60019150148261273a565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760208260009080600052600b8352604060002060ff815460f01c16806127e4575b6127bb575b50506001600160801b0360405191168152f35b6127dd92506001600160801b0360026127d79201541691613add565b90612d57565b82806127a8565b5060ff600182015460a01c16156127a3565b50346102ca5760403660031901126102ca57612810612b2e565b906024359061281e82613aa2565b90331515806128ea575b806128bc575b61288b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260076020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600860205260406000203360005260205260ff604060002054161561282e565b50336001600160a01b0383161415612828565b50346102ca5760203660031901126102ca57611b1060209135612d33565b50346102ca5760003660031901126102ca576040519060006003549060018260011c92600181168015612a0e575b60209586861082146129f9575084875286939291869082156129d957505060011461297c575b50610d6c92500383612ce1565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106129c1575050610d6c93508201013861296f565b805483890185015287945086939092019181016129aa565b60ff191685820152610d6c95151560051b850101925038915061296f9050565b602290634e487b7160e01b6000525260246000fd5b93607f1693612949565b82346102ca5760203660031901126102ca5735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102ca57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612abc575b8115612a92575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612a8b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612a84565b60005b838110612af95750506000910152565b8181015183820152602001612ae9565b90602091612b2281518092818552858086019101612ae6565b601f01601f1916010190565b600435906001600160a01b03821682036102ca57565b602435906001600160a01b03821682036102ca57565b35906001600160a01b03821682036102ca57565b60609060031901126102ca576001600160a01b039060043582811681036102ca579160243590811681036102ca579060443590565b9181601f840112156102ca5782359167ffffffffffffffff83116102ca576020808501948460051b0101116102ca57565b90815180825260208080930193019160005b828110612bf4575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612be6565b359081151582036102ca57565b610120810190811067ffffffffffffffff821117612c6257604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612c6257604052565b6040810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257604052565b610140810190811067ffffffffffffffff821117612c6257604052565b90601f8019910116810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257601f01601f191660200190565b35906001600160801b03821682036102ca57565b612d3c81613aa2565b5060005260076020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612d7057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612fb75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c16159081612fad575b5080612fa5575b612f8e578685526005815282848620541694873315159384612ede575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612ea6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612e785750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612ec782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055612e14565b91929380915090612f4d575b15612ef85790878392612deb565b848887612f15576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612f72575b80612eea5750878252600783523384868420541614612eea565b5085825260088352848220338352835260ff8583205416612f58565b602487855190630da9b01360e01b82526004820152fd5b506001612dce565b9050151538612dc7565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff821682036102ca57565b67ffffffffffffffff8111612c625760051b60200190565b92919261300582612fe1565b6040946130156040519283612ce1565b819584835260208093019160608096028501948186116102ca57925b8584106130415750505050505050565b86848303126102ca5782519061305682612c78565b61305f85612d1f565b8252858501359067ffffffffffffffff821682036102ca57828792838b95015261308a868801612fcf565b86820152815201930192613031565b91908260409103126102ca576040516130b181612c94565b60208082946130bf81612b5a565b84520135910152565b91908110156130d85760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102ca5790565b356001600160a01b03811681036102ca5790565b3580151581036102ca5790565b6040519061313082612c78565b60006040838281528260208201520152565b9060405161314f81612c78565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b90815461318281612fe1565b926040936131936040519182612ce1565b82815280946020809201926000526020600020906000935b8585106131ba57505050505050565b600184819284516131ca81612c78565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c16868201528152019301940193916131ab565b9190613213828285612d86565b803b613220575b50505050565b61327c6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612b09565b03906020816000938185885af190829082613312575b50506132c957826132a161464a565b80519190826132c25760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036132fa57503880808061321a565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613372575b8161332f60209383612ce1565b8101031261336e5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361336b5750903880613292565b80fd5b5080fd5b3d9150613322565b92919092613386613d21565b600093818552600b9260209380855260409260ff6001858a20015460a81c16156137065784885281865260ff6001858a20015460a01c166136ef576001600160a01b03918282169283156136df576001600160801b03938486169182156136c857888c5260058a5280888d2054169384831415806136b8575b6136955761340c8a61467a565b878116851161366457508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061343d916146a2565b878752838652828720600201908282549160801b6001600160801b031916911617815561346990613142565b90808683015116918184818351169201511661348491612d57565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d96613637575b878252855220015416946134c78189886145ee565b8a51908152a4803314158061362d575b6135c8575b8233141590816135bd575b816135b2575b50613521575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156135ae578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af161359f575b8594816134f3565b6135a890612cb0565b38613597565b8780fd5b9050821415386134ed565b833b151591506134e7565b803b15613629578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af161361a575b506134dc565b61362390612cb0565b38613614565b8880fd5b50803b15156134d7565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134b2565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506136c28a614585565b156133ff565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b92919092600093818552600b9060209382855260409260ff6001858a20015460a81c1615613706578785815281875260ff6001868320015460a01c16613a8b576001600160a01b0390818516928315613a7b576001600160801b0393848616918215613a645789845260058b52848985205416948583141580613a54575b613a31576137c18b838e6137ad83614b1c565b9289525260028c8820015460801c90612d57565b8781168511613a005750908b8b928387528282528b808820998b838c54169b6002015460801c906137f1916146a2565b868a52858552828a20600201908282549160801b6001600160801b031916911617815561381d90613142565b8180868301511693818351169201511661383691612d57565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936139d2575b848852825260018c88200154169461387a818c886145ee565b8b51908152a481331415806139c8575b613962575b50813314159081613957575b8161394c575b506138d4575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613948578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613930575b80806134f3565b61393a8691612cb0565b6139445784613929565b8480fd5b8280fd5b9050811415386138a1565b823b1515915061389b565b813b1561336b578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16139b4575b5061388f565b6139c091929a50612cb0565b9738806139ae565b50813b151561388a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613861565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b50613a5e8b614585565b1561379a565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260056020526001600160a01b0360406000205416908115613ac5575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c161015613b4b5760c81c161115613b395750600c602052600160406000205411600014613b3057613b2d9061478e565b90565b613b2d906146bd565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c16600014613b7c575050600490565b805460f81c613bd5575460a01c64ffffffffff164210613bcf57613b9f81613add565b90600052600b6020526001600160801b038060026040600020015416911610600014613bca57600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613d17575b5080613d0c575b613cf5579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613cbd575b169283613ca7575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613c83565b613cde86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613c7b565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c1a565b9050151538613c13565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613d5357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b8051156130d85760200190565b80518210156130d85760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106d157600090614551575b613e2091506001600160801b0360408501511690602061010086015101519161496e565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452757815180156144fd577f000000000000000000000000000000000000000000000000000000000000000081116144cc575064ffffffffff6040613e8384613d7d565b510151168110156144755750600090819082815184905b8082106143e4575050505064ffffffffff421664ffffffffff82168110156143a45750506001600160801b031680820361436d5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000604061402d8951996000198b0190613d8a565b51015160c81b169560f01b16911617171717845560005b81811061429b575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b036020830151168015612fb7576140cf866001600160a01b0392613bdc565b1661426a576141046001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614aad565b6001600160801b036040820151168061423a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6141f76001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661422f61420f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a38c612c94565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190612bd4565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b614264906001600160a01b036060850151166001600160a01b036101008601515116903390614aad565b38614118565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906142b88160e0870151613d8a565b51825468010000000000000000811015612c6257600181018085558110156130d857600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501614044565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614408906001600160801b036143ff8588613d8a565b515116906146a2565b9364ffffffffff80604061441c8685613d8a565b5101511694168085111561443857506001849301909291613e9a565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061448684613d7d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161457d575b8161456b60209383612ce1565b810103126102ca57613e209051613dfc565b3d915061455e565b60009080825260056020526001600160a01b0380604084205416928333149384156145ca575b505082156145b857505090565b9091506145c53392612d33565b161490565b60ff92945090604091815260086020528181203382526020522054169138806145ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261464891614643606483612ce1565b614b97565b565b3d15614675573d9061465b82612d03565b916146696040519384612ce1565b82523d6000602084013e565b606090565b613b2d9061468781614b1c565b90600052600b60205260026040600020015460801c90612d57565b9190916001600160801b0380809416911601918211612d7057565b64ffffffffff6146f2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614c33565b91808252600c6020526040822080541561477a5790829167ffffffffffffffff935261474c6020832054828452600b6020526147476001600160801b03968760026040882001541696879360801c1690614d23565b614d91565b92831361476257505061475e90614e7b565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff8042166000838152600b602052604091828220908351916147b483612cc4565b80549661012061483a60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201613142565b94019384528452600c602052614851858520613176565b918496808761485f86613d7d565b5101511692828288955b16106149385750916148ed614747928488816148f298976001600160801b039e8f614894898c613d8a565b5151169d8e9a67ffffffffffffffff60206148af8c84613d8a565b510151169984836148c08385613d8a565b510151169650801561492c576148dc9293506000190190613d8a565b5101511680925b0316920316614c33565b614d23565b92831361490b5750506149058391614e7b565b16011690565b5160200151929392831692841683101591506149279050575090565b905090565b505050511680926148e3565b8093986001600160801b03908161494f8c89613d8a565b51511601169801928282808a614965888a613d8a565b51015116614869565b909291614979613123565b936001600160801b0392838116918215614a855767016345785d8a0000808211614a4e57808511614a1757506149c3856149b48193866159a7565b169460208901958652846159a7565b1691846149da6040890194808652828751166146a2565b161015614a01576149f38491826149fc95511690612d57565b91511690612d57565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614a9881612c78565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612c625761464892604052614b97565b80600052600b602052614b356002604060002001613142565b81600052600b602052604060002060ff600182015460a01c16600014614b6857506001600160801b039150602001511690565b5460f81c614b7a5750613b2d90613add565b613b2d91506001600160801b036040818351169201511690612d57565b6001600160a01b031690614bc2600080836020829551910182875af1614bbb61464a565b9084615a56565b908151918215159283614c0b575b505050614bda5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261336e57602001519081159182150361336b5750388080614bd0565b600160ff1b808214908115614d19575b50614cef576000811215614ce657614c6c816000035b6000841215614cdf578360000390614eb7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614ca85760001991181315614ca25790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614eb7565b614c6c81614c59565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c43565b80614d3e5750614d3957670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614d8b575080614d63575050670de0b6b3a764000090565b670de0b6b3a76400008114614d8757614d8290614747613b2d93614fb1565b6150f3565b5090565b91505090565b600160ff1b808214908115614e71575b50614e47576000811215614e3e57614dca816000035b6000841215614e375783600003906159a7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614e005760001991181315614ca25790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906159a7565b614dca81614db7565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614da1565b60008112614e865790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614f735782851015614f3757908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614f81570490565b634e487b7160e01b600052601260045260246000fd5b8015614f81576ec097ce7bc90715b34b9f10000000000590565b806000808313156150c257670de0b6b3a76400009283811261509f57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d9082821461509357506706f05b59d3b20000905b8482136150675750505050500290565b808391020590671bc16d674ec80000821215615086575b831d90615057565b8091950194831d9061507e565b93505093925050020290565b6000199392508015614f81576ec097ce7bc90715b34b9f10000000000591614fd2565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60008112156151225768033dd1780914b97114198112613bcf57615119906000036150f3565b613b2d90614f97565b680a688906bd8affffff811361597657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615859575b66ff0000000000008316615751575b65ff00000000008316615651575b64ff000000008316615559575b63ff0000008316615469575b62ff00008316615381575b61ff0083166152a1575b60ff83166151ca575b02911c60bf031c90565b6080831661528f575b83831661527d575b6020831661526b575b60108316615259575b60088316615247575b60048316615235575b60028316615223575b60018316156151c0576801000000000000000102831c6151c0565b6801000000000000000102831c615208565b6801000000000000000302831c6151ff565b6801000000000000000602831c6151f6565b6801000000000000000b02831c6151ed565b6801000000000000001602831c6151e4565b6801000000000000002c02831c6151db565b6801000000000000005902831c6151d3565b618000831661536f575b614000831661535d575b612000831661534b575b6110008316615339575b6108008316615327575b6104008316615315575b6102008316615303575b6101008316156151b757680100000000000000b102831c6151b7565b6801000000000000016302831c6152e7565b680100000000000002c602831c6152dd565b6801000000000000058c02831c6152d3565b68010000000000000b1702831c6152c9565b6801000000000000162e02831c6152bf565b68010000000000002c5d02831c6152b5565b680100000000000058b902831c6152ab565b628000008316615457575b624000008316615445575b622000008316615433575b621000008316615421575b62080000831661540f575b6204000083166153fd575b6202000083166153eb575b620100008316156151ad576801000000000000b17202831c6151ad565b680100000000000162e402831c6153ce565b6801000000000002c5c802831c6153c3565b68010000000000058b9102831c6153b8565b680100000000000b172102831c6153ad565b68010000000000162e4302831c6153a2565b680100000000002c5c8602831c615397565b6801000000000058b90c02831c61538c565b63800000008316615547575b63400000008316615535575b63200000008316615523575b63100000008316615511575b630800000083166154ff575b630400000083166154ed575b630200000083166154db575b63010000008316156151a25768010000000000b1721802831c6151a2565b6801000000000162e43002831c6154bd565b68010000000002c5c86002831c6154b1565b680100000000058b90c002831c6154a5565b6801000000000b17217f02831c615499565b680100000000162e42ff02831c61548d565b6801000000002c5c85fe02831c615481565b68010000000058b90bfc02831c615475565b648000000000831661563f575b644000000000831661562d575b642000000000831661561b575b6410000000008316615609575b64080000000083166155f7575b64040000000083166155e5575b64020000000083166155d3575b64010000000083161561519657680100000000b17217f802831c615196565b68010000000162e42ff102831c6155b4565b680100000002c5c85fe302831c6155a7565b6801000000058b90bfce02831c61559a565b68010000000b17217fbb02831c61558d565b6801000000162e42fff002831c615580565b68010000002c5c8601cc02831c615573565b680100000058b90c0b4902831c615566565b65800000000000831661573f575b65400000000000831661572d575b65200000000000831661571b575b651000000000008316615709575b6508000000000083166156f7575b6504000000000083166156e5575b6502000000000083166156d3575b65010000000000831615615189576801000000b17218355102831c615189565b680100000162e430e5a202831c6156b3565b6801000002c5c863b73f02831c6156a5565b68010000058b90cf1e6e02831c615697565b680100000b1721bcfc9a02831c615689565b68010000162e43f4f83102831c61567b565b680100002c5c89d5ec6d02831c61566d565b6801000058b91b5bc9ae02831c61565f565b66800000000000008316615847575b66400000000000008316615835575b66200000000000008316615823575b66100000000000008316615811575b660800000000000083166157ff575b660400000000000083166157ed575b660200000000000083166157db575b660100000000000083161561517b5768010000b17255775c0402831c61517b565b6801000162e525ee054702831c6157ba565b68010002c5cc37da949202831c6157ab565b680100058ba01fb9f96d02831c61579c565b6801000b175effdc76ba02831c61578d565b680100162f3904051fa102831c61577e565b6801002c605e2e8cec5002831c61576f565b68010058c86da1c09ea202831c615760565b6780000000000000008316615957575b6740000000000000008316615945575b6720000000000000008316615933575b6710000000000000008316615921575b670800000000000000831661590f575b67040000000000000083166158fd575b67020000000000000083166158eb575b67010000000000000083161561516c57680100b1afa5abcbed6102831c61516c565b68010163da9fb33356d802831c6158c9565b680102c9a3e778060ee702831c6158b9565b6801059b0d31585743ae02831c6158a9565b68010b5586cf9890f62a02831c615899565b6801172b83c7d517adce02831c615889565b6801306fe0a31b7152df02831c615879565b5077b504f333f9de648480000000000000000000000000000000615869565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b90919060001983820983820291828083109203918083039214615a4557670de0b6b3a76400009081831015615a0e57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90615a955750805115615a6b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615ae0575b615aa6575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15615a9e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003e757601f196001600160401b03601f62004dd23881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516149af9081620004238239608051816138980152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f205750806306fdde0314612e5c578063081812fc14612e3d578063095ea7b314612cae5780631400ecec14612c0e5780631c1cdd4c14612ba95780631e99d56914612b8b57806323b872dd14612b6157806339a73c0314612b2057806340e58ee51461289a578063425d30dd1461287b57806342842e0e1461282b57806342966c68146126c1578063442675701461269a5780634857501f146126105780634869e12d146125d55780634cc55e111461217057806353b15727146120515780635fe3b5671461202a5780636352211e1461200b5780636d0cee7514611fb557806370a0823114611f0c57806375829def14611e79578063780a82c814611e295780637cad6cd114611d585780637de6b1db14611b485780638659c27014611831578063894e9a0d146115dd5780638bad38dd146115605780638f69b993146114c45780639067b6771461147157806395d89b4114611362578063a22cb46514611291578063a6202bf214611194578063a80fc07114611142578063ab167ccc14611008578063ad35efd414610fa6578063b256456914610f87578063b88d4fde14610efd578063b8a3be6614610ec8578063b971302a14610e98578063bc063e1a14610e75578063bc2be1be14610e25578063c156a11d14610a32578063c87b56dd146108f8578063cc364f481461084a578063d4dbd20b146107f8578063d511609f146107ac578063d975dfed14610760578063e985e9c51461070b578063ea5ead19146106e3578063eac8f5b81461067a578063f590c17614610651578063f851a4401461062b5763fdd46d601461027e57600080fd5b34610628576060366003190112610628576004359061029b61304f565b916102a461318f565b6102ac61388e565b6102b582613282565b610610576001600160a01b03908185169485156105e6576001600160801b03918281169384156105ce57858752602094600586528160408920541690818a1415806105be575b61059a5761030888614277565b868116821161056457508899610320899a989961346f565b968a8952600b8a5261037761033f87600260408d20015460801c61429f565b8c8b52600b8c52610372600260408d20019182906001600160801b036001600160801b031983549260801b169116179055565b61336e565b90610393818c84015116928260408183511692015116906131e2565b161115610534575b898852600b8952897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8a86600160408d20015416946103db818b8861420f565b604051908152a4803314158061052a575b6104b5575b508316928333141590816104aa575b50610434575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a657604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048e575b8080610406565b610497906130cb565b6104a2578238610487565b8280fd5b8380fd5b90503b151538610400565b803b1561052657604051636fd110e960e01b8152600481018990523360248201526001600160a01b03851660448201526001600160801b0384166064820152869182908290608490829084905af161050e575b506103f1565b610517906130cb565b610522578438610508565b8480fd5b8580fd5b50803b15156103ec565b898852600b89526040882060018101600160c81b60ff60c81b1982541617905560ff60f01b19815416905561039b565b60405163287ecaef60e21b8152600481018a90526001600160801b038681166024830152919091166044820152606490fd5b0390fd5b6064888b6040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8886138ea565b156102fb565b6024866040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248260405190634a5541ef60e01b82526004820152fd5b80fd5b50346106285780600319360112610628576001600160a01b036020915416604051908152f35b50346106285760203660031901126106285760206106706004356134a6565b6040519015158152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760016040836001600160a01b039360209552600b855220015416604051908152f35b6024906040519062b8e7e760e51b82526004820152fd5b5034610628576040366003190112610628576004359061070161304f565b916102a481614277565b503461062857604036600319011261062857610725613039565b604061072f61304f565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106285760203660031901126106285760ff6001604060043593848152600b60205220015460d01c16156106cc5761079b602091614277565b6001600160801b0360405191168152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408260029260209452600b845220015460801c604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760036040836001600160801b039360209552600b855220015416604051908152f35b50346106285760203660031901126106285760043561086761334f565b50808252600b60205260ff600160408420015460d01c16156106cc578160409160609352600b60205220600181549164ffffffffff918291015460a01c1690604051926108b3846130fc565b818160a01c16845260c81c16602083015260408201526108f660405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b503461062857602080600319360112610a22576004356109366109318260005260056020526001600160a01b0360406000205416151590565b6132df565b826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a265780936109a5575b50506109a1604051928284938452830190613014565b0390f35b909192503d8082843e6109b88184613151565b8201918381840312610a225780519067ffffffffffffffff82116104a2570182601f82011215610a22578051916109ee83613173565b936109fc6040519586613151565b838552858484010111610628575090610a1a91848085019101612ff1565b90388061098b565b5080fd5b604051903d90823e3d90fd5b503461062857604036600319011261062857600435610a4f61304f565b90610a5861388e565b808352602091600b835260ff600160408620015460d01c1615610e0e57818452600583526001600160a01b038060408620541690813303610def57610a9c84614277565b906001600160801b039081831680158015610ac1575b89610abe8989896136f3565b80f35b610ac961388e565b610ad288613282565b610dd75785156105e657610dbf57868952600588528160408a205416908186141580610daf575b610d8b57610b0688614277565b8481168211610d595750908994939291610b1f8961346f565b93898752600b8b52610b71610b3e87600260408b20015460801c61429f565b8b8952600b8d52610372600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b8d818d84015116928260408183511692015116906131e2565b161115610d29575b888652600b8a5286897f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d8c86600160408c2001541694610bd681868861420f565b604051908152a48033141580610d1f575b610cb2575b50811690813314159081610ca7575b50610c3a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7610abe94604051858152a13880808080610ab2565b803b156104a257604051636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b0392909216606483015282908290608490829084905af1610c93575b80610c01565b610c9c906130cb565b610522578438610c8d565b90503b151538610bfb565b803b1561052257604051636fd110e960e01b8152600481018990523360248201526001600160a01b03871660448201526001600160801b0385166064820152859182908290608490829084905af1610d0b575b50610bec565b610d14906130cb565b6104a6578338610d05565b50803b1515610be7565b888652600b8a526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055610b95565b60405163287ecaef60e21b8152600481018a90526001600160801b038781166024830152919091166044820152606490fd5b606488876040519163b34359d360e01b835260048301523360248301526044820152fd5b50610db9886138ea565b15610af9565b6024876040519063d2aabcd960e01b82526004820152fd5b60248860405190634a5541ef60e01b82526004820152fd5b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610628578060031936011261062857602060405167016345785d8a00008152f35b5034610628576020366003190112610628576020610eb760043561346f565b6001600160a01b0360405191168152f35b50346106285760203660031901126106285760ff600160406020936004358152600b855220015460d01c166040519015158152f35b503461062857608036600319011261062857610f17613039565b610f1f61304f565b906064359067ffffffffffffffff82116104a657366023830112156104a65781600401359284610f4e85613173565b93610f5c6040519586613151565b8585523660248783010111610a225785610abe966024602093018388013785010152604435916133d9565b50346106285760203660031901126106285760206106706004356133a2565b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57610fdf9061358d565b604051906005811015610ff457602092508152f35b602483634e487b7160e01b81526021600452fd5b5034610628576101403660031901126106285761102361388e565b61102b61334f565b9064ffffffffff80421680845260c435828116810361113d5781018216602085015260e43590818316820361113d5701166040830152600435916001600160a01b039182841680940361113d576024359083821680920361113d57604435906001600160801b03821680920361113d576064359085821680920361062857506084359182151580930361113d5760a4359384151580950361113d57604051976110d3896130df565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261113d576040519161110d83613135565b61010435918216820361113d57826111359260209452610124358482015260e08201526139ce565b604051908152f35b600080fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760026040836001600160801b039360209552600b855220015416604051908152f35b5034610628576020366003190112610628576111ae613039565b6001600160a01b0380835416338103611268575081169081835260026020526001600160801b036040842054169081156112375781611208918486526002602052604086206001600160801b03198154169055339061420f565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610628576040366003190112610628576112ab613039565b6024359081151580920361113d576001600160a01b03169081331461131e5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b606460405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b503461062857806003193601126106285760405190806004549160018360011c9260018516948515611467575b6020958686108114611453578588528794939291879082156114315750506001146113d7575b50506113c392500383613151565b6109a1604051928284938452830190613014565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8583106114195750506113c3935082010138806113b5565b80548389018501528794508693909201918101611401565b92509350506113c394915060ff191682840152151560051b82010138806113b5565b602483634e487b7160e01b81526022600452fd5b93607f169361138f565b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57600160408364ffffffffff9360209552600b855220015460a01c16604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc576114fd9061358d565b906005821015908161153e5760028314918215611552575b8215611529575b6020836040519015158152f35b90915061153e5750600460209114388061151c565b80634e487b7160e01b602492526021600452fd5b506003831491506000611515565b5034610628576020366003190112610628576004356001600160a01b03908181168091036104a25781835416338103611268575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b5034610628576020366003190112610628576040516115fb81613118565b8181528160208201528160408201528160608201528160808201528160a08201528160c08201528160e0820152816101008201528161012082015261014061164161334f565b9101526004358152600b60205260ff600160408320015460d01c1615611819576004358152600b6020526040812061171a60026040519261168184613118565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a087015264ffffffffff8160a01c1660c0870152818160c81c16151560e0870152818160d01c16151561010087015260d81c1615156101208501520161336e565b61014082015261172b60043561358d565b6005811015610ff4579160026101a0931461180e575b506108f6610140604051926001600160a01b03815116845264ffffffffff602082015116602085015264ffffffffff60408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a085015264ffffffffff60c08201511660c085015260e0810151151560e0850152610100810151151561010085015261012081015115156101208501520151610140830190604090816001600160801b0391828151168552826020820151166020860152015116910152565b606082015238611741565b602460405162b8e7e760e51b81526004356004820152fd5b503461062857602080600319360112610a225760043567ffffffffffffffff81116104a25761186490369060040161309a565b919061186e61388e565b83925b80841061187c578480f35b6118878482846132b9565b359361189161388e565b61189a85613282565b156118b75760248560405190634a5541ef60e01b82526004820152fd5b909192936118c4816134a6565b611b30576118e881600052600b6020526001600160a01b0360406000205416331490565b15611b10576118f6816134d7565b90808752600b9081875261190f600260408a200161336e565b916001600160801b0393848451168582161015611af857828a5281895260ff60408b205460f01c1615611ae0579061195e82868b6119548897968f9a809a51166131e2565b96015116906131e2565b91808652818a5260408620938a8554600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82161787556003888716978815611ac6575b0197831697886001600160801b03198254161790557f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506001600160a01b03809216968792600585528060408d20541697889552600160408d2001541694611a0b8b858861420f565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a6f575b505050505050600101929190611871565b813b1561052657856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611ab2575b80808080611a5e565b611abb906130cb565b610522578438611aa9565b60018101600160c81b60ff60c81b198254161790556119a3565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b503461062857602080600319360112610a225760043590611b6761388e565b818352600b815260ff600160408520015460d01c1615610e0e57611b8a8261358d565b6005811015611d445760048103611bb35760248360405190634a5541ef60e01b82526004820152fd5b60038103611bd3576024836040519063fe19f19f60e01b82526004820152fd5b600214611d2c57611bfa82600052600b6020526001600160a01b0360406000205416331490565b15611d0d57818352600b815260ff604084205460f01c1615611cf557818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b611c9d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a257816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611ce1575b80611c6e565b611cea906130cb565b6104a2578238611cdb565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b5034610628576020366003190112610628576004356001600160a01b03908181168091036104a257818354163381036112685750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101908111611e155760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461062857602036600319011261062857611e93613039565b9080546001600160a01b0380821693338503611ee5576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610628576020366003190112610628576001600160a01b03611f2e613039565b168015611f4b578160409160209352600683522054604051908152f35b608460405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152fd5b5034610628576020366003190112610628576001600160a01b036040602092600435611ffa6109318260005260056020526001600160a01b0360406000205416151590565b815260058452205416604051908152f35b5034610628576020366003190112610628576020610eb760043561332a565b503461062857806003193601126106285760206001600160a01b0360015416604051908152f35b5034610628576101603660031901126106285761206c61388e565b60405190612079826130df565b612081613039565b825261208b61304f565b602083015261209861318f565b60408301526001600160a01b0390606435828116810361113d576060840152608435801515810361113d57608084015260a435801515810361113d5760a084015260603660c319011261062857506040516120f2816130fc565b64ffffffffff60c435818116810361113d57825260e435818116810361113d57602083015261010435908116810361113d57604082015260c083015260406101231936011261113d576040519161214883613135565b61012435918216820361113d57826111359260209452610144358482015260e08201526139ce565b50346106285760403660031901126106285767ffffffffffffffff6004358181116104a2576121a390369060040161309a565b90916024359081116104a6576121bd90369060040161309a565b6121c561388e565b80830361259e57845b8381106121d9578580f35b6121e48185876132b9565b35906121f18186886132b9565b35875260056020526001600160a01b036040882054166122128285876132b9565b35906001600160801b038216820361113d5761222c61388e565b61223584613282565b6125865780156105e6576001600160801b0382161561256e5783895260056020526001600160a01b0360408a20541691828214158061255e575b61253a5761227c85614277565b6001600160801b0381166001600160801b0383161161250a5750908992916122a38661346f565b92868552600b806020526122f760026103726122c8868360408c20015460801c61429f565b918b8a528460205260408a20019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361231b81602084015116928260408183511692015116906131e2565b1611156124da575b8786526020526001600160a01b0360016040872001541661234e6001600160801b038416858361420f565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806124d0575b612463575b506001600160a01b03831692833314159081612458575b506123e6575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016121ce565b823b156104a657604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612440575b80806123af565b612449906130cb565b612454578638612439565b8680fd5b90503b1515386123a9565b803b1561052257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b0383166064820152859182908290608490829084905af16124bc575b50612392565b6124c5906130cb565b6104a65783386124b6565b50803b151561238d565b878652806020526040862060018101600160c81b60ff60c81b1982541617905560ff60f01b198154169055612323565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b50612568856138ea565b1561226f565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106285760203660031901126106285760ff6001604060043593848152600b60205220015460d01c16156106cc5761079b602091613953565b50346106285760203660031901126106285760043590818152600b60205260ff600160408320015460d01c1615610e0e578061264b8361358d565b9260058410156126865760026020940361266c575b50506040519015158152f35b8152600b8352604090205460f01c60ff1690503880612660565b602482634e487b7160e01b81526021600452fd5b503461062857806003193601126106285760206001600160a01b03600a5416604051908152f35b5034610628576020366003190112610628576004356126de61388e565b6126e781613282565b156127fa576126f5816138ea565b15611b10576127038161332a565b61270c826133a2565b1590816127f2575b816127df575b506127c75760208161274c7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79361332a565b90808552600783526001600160a01b0360408620926001600160a01b03199384815416905516918286526006845260408620600019815401905581865260058452604086209081541690558085604051937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a48152a180f35b60249060405190630da9b01360e01b82526004820152fd5b6001600160a01b0391501615153861271a565b839150612714565b602490604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106285761283a36613065565b60405191602083019383851067ffffffffffffffff86111761286557610abe946040528584526133d9565b634e487b7160e01b600052604160045260246000fd5b5034610628576020366003190112610628576020610670600435613282565b503461062857602080600319360112610a2257600435906128b961388e565b6128c282613282565b156128df5760248260405190634a5541ef60e01b82526004820152fd5b906128e9816134a6565b611b305761290d81600052600b6020526001600160a01b0360406000205416331490565b15611b105761291b816134d7565b818452600b83526129316002604086200161336e565b926001600160801b0391828551168382161015612b0857838652600b825260ff604087205460f01c1615612af05792827ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7836129a6878460409761299c8d9b612a519b8e51166131e2565b9b015116906131e2565b92848852600b825287868120947f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50865491600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84161788556003858216988915612ad6575b01948d169c858e6001600160801b0319819854161790556001600160a01b038094169b8c94600589526001818e892054169d8e98600b8c522001541696858861420f565b604080518b81526001600160801b0392831660208201529290911690820152606090a4604051848152a1823b612a85578480f35b823b15610522576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612ac7575b81818080808480f35b612ad0906130cb565b38612abe565b60018101600160c81b60ff60c81b19825416179055612a0d565b602484604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b5034610628576020366003190112610628576001600160801b0360406020926001600160a01b03612b4f613039565b16815260028452205416604051908152f35b503461062857610abe612b7336613065565b91612b86612b818433613614565b613211565b6136f3565b50346106285780600319360112610628576020600954604051908152f35b503461062857602036600319011261062857600435808252600b60205260ff600160408420015460d01c16156106cc57612be29061358d565b90600582101561153e5760208215838115612c03575b506040519015158152f35b600191501482612bf8565b50346106285760203660031901126106285760043590818152600b60205260ff600160408320015460d01c1615610e0e57602091604082828152600b85522060ff815460f01c1680612c9c575b612c73575b50506001600160801b0360405191168152f35b612c9592506001600160801b036002612c8f92015416916134d7565b906131e2565b3880612c60565b5060ff600182015460c81c1615612c5b565b503461062857604036600319011261062857612cc8613039565b602435906001600160a01b038080612cdf8561332a565b16921691808314612dd357803314908115612db2575b5015612d4857828452600760205260408420826001600160a01b0319825416179055612d208361332a565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b608460405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b9050845260086020526040842033855260205260ff60408520541638612cf5565b608460405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b5034610628576020366003190112610628576020610eb76004356131a5565b503461062857806003193601126106285760405190806003549160018360011c9260018516948515612f16575b602095868610811461145357858852879493929187908215611431575050600114612ebc5750506113c392500383613151565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b858310612efe5750506113c3935082010138806113b5565b80548389018501528794508693909201918101612ee6565b93607f1693612e89565b905034610a22576020366003190112610a22576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a257602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115612fc7575b8115612f9d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612f96565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612f8f565b60005b8381106130045750506000910152565b8181015183820152602001612ff4565b9060209161302d81518092818552858086019101612ff1565b601f01601f1916010190565b600435906001600160a01b038216820361113d57565b602435906001600160a01b038216820361113d57565b606090600319011261113d576001600160a01b0390600435828116810361113d5791602435908116810361113d579060443590565b9181601f8401121561113d5782359167ffffffffffffffff831161113d576020808501948460051b01011161113d57565b67ffffffffffffffff811161286557604052565b610100810190811067ffffffffffffffff82111761286557604052565b6060810190811067ffffffffffffffff82111761286557604052565b610160810190811067ffffffffffffffff82111761286557604052565b6040810190811067ffffffffffffffff82111761286557604052565b90601f8019910116810190811067ffffffffffffffff82111761286557604052565b67ffffffffffffffff811161286557601f01601f191660200190565b604435906001600160801b038216820361113d57565b6131c86109318260005260056020526001600160a01b0360406000205416151590565b60005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116131fb57565b634e487b7160e01b600052601160045260246000fd5b1561321857565b608460405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f766564000000000000000000000000000000000000006064820152fd5b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260ff60016040600020015460c81c1690565b91908110156132c95760051b0190565b634e487b7160e01b600052603260045260246000fd5b156132e657565b606460405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152fd5b60005260056020526001600160a01b036040600020541661334c8115156132df565b90565b6040519061335c826130fc565b60006040838281528260208201520152565b9060405161337b816130fc565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260ff60016040600020015460d81c1690565b906133fd9392916133ed612b818433613614565b6133f88383836136f3565b6145e8565b1561340457565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b6020526001600160a01b036040600020541690565b80600052600b60205260ff60016040600020015460d01c16156106cc57600052600b60205260406000205460f81c90565b600090808252600b6020526040822091825464ffffffffff42818360c81c16116135855780600186015460a01c16918242101561356f576135249394955060a01c1680910390420361477b565b90828152600b6020526001600160801b039261354a84600260408520015416809461485b565b9283116135575750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b505091505090565b80600052600b602052604060002060ff600182015460c81c166000146135b4575050600490565b805460f81c61360d575460a01c64ffffffffff164210613607576135d7816134d7565b90600052600b6020526001600160801b03806002604060002001541691161060001461360257600190565b600290565b50600090565b5050600390565b906001600160a01b0380806136288461332a565b1693169183831493841561365b575b508315613645575b50505090565b613651919293506131a5565b161438808061363f565b909350600052600860205260406000208260005260205260ff604060002054169238613637565b1561368957565b608460405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152fd5b9061371c92916137028361332a565b916001600160a01b03948593848094169687911614613682565b16908115806138255761372e846133a2565b15908161381c575b5080613813575b6137fb579180849261377d7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7966020966137768561332a565b1614613682565b60009382855260078652604085206001600160a01b031990818154169055818652600687526040862060001981540190558286526040862060018154019055838652600587528260408720918254161790557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6040519580a48152a1565b60248360405190630da9b01360e01b82526004820152fd5b5083151561373d565b90501538613736565b608460405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036138c057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b03806040842054169283331493841561392f575b5050821561391d57505090565b90915061392a33926131a5565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613910565b80600052600b60205261396c600260406000200161336e565b81600052600b602052604060002060ff600182015460c81c1660001461399f57506001600160801b039150602001511690565b5460f81c6139b1575061334c906134d7565b61334c91506001600160801b0360408183511692015116906131e2565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa8015614203576000906141cf575b613a4f91506001600160801b0360408501511690602060e08601510151916142ba565b916001600160801b0383511660c082015190156141a55764ffffffffff815116602082019064ffffffffff8251169081811161416557505064ffffffffff604091511691019064ffffffffff825116908181101561412557505064ffffffffff80421691511690818110156140e5575050600954926001600160801b0381511660405190613adc826130fc565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff6020840151169064ffffffffff604085015116906080870151151560a088015115159364ffffffffff6001600160a01b038a511697511660405197613b4b89613118565b88526020880152604087015260608601526000608086015260a085015260c0840152600060e0840152600161010084015261012083015261014082015284600052600b60205260406000206001600160a01b038251166001600160a01b0319825416178155613be264ffffffffff602084015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b604082015181547eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b169078ffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffff000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006080880151151560f81b169460c81b1691161717178155600181016001600160a01b0360a0840151166001600160a01b0319825416178155613cd964ffffffffff60c085015116829064ffffffffff60a01b1964ffffffffff60a01b83549260a01b169116179055565b60e083015181546101008501516101208601517fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff90921692151560c81b79ff00000000000000000000000000000000000000000000000000169290921791151560d01b7aff0000000000000000000000000000000000000000000000000000169190911790151560d81b7bff00000000000000000000000000000000000000000000000000000016179055610140909101518051602082015160801b6001600160801b03199081166001600160801b03928316176002850155926040906003019201511682825416179055600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b0360208301511680156140a157613e54613e4e8660005260056020526001600160a01b0360406000205416151590565b156143f9565b613e5d856133a2565b1580614098575b80614090575b6140785760207ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791613eb5613e4e8860005260056020526001600160a01b0360406000205416151590565b806000526006825260406000206001815401905586600052600582526040600020816001600160a01b0319825416179055866040519160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4868152a1613f456001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614444565b6001600160801b0360408201511680614049575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140406001600160a01b03606089015116976080810151151560a082015115159061400a6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b614072906001600160a01b036060850151166001600160a01b0360e08601515116903390614444565b38613f59565b60248560405190630da9b01360e01b82526004820152fd5b506000613e6a565b50801515613e64565b606460405162461bcd60e51b815260206004820152602060248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f4c23297000000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116141fb575b816141e960209383613151565b8101031261113d57613a4f9051613a2c565b3d91506141dc565b6040513d6000823e3d90fd5b916001600160a01b03604051927fa9059cbb000000000000000000000000000000000000000000000000000000006020850152166024830152604482015260448152608081019181831067ffffffffffffffff84111761286557614275926040526144af565b565b61334c9061428481613953565b90600052600b60205260026040600020015460801c906131e2565b9190916001600160801b03808094169116019182116131fb57565b9092916142c561334f565b936001600160801b03928381169182156143d15767016345785d8a000080821161439a57808511614363575061430f8561430081938661485b565b1694602089019586528461485b565b16918461432660408901948086528287511661429f565b16101561434d5761433f849182614348955116906131e2565b915116906131e2565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516143e4816130fc565b60008152600060208201526000604082015290565b1561440057565b606460405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152fd5b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761286557614275926040525b6001600160a01b03169061450f6040516144c881613135565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16145096145b8565b9161490a565b805191821591848315614594575b50505090501561452a5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b919381809450010312610a225782015190811515820361062857508038808461451d565b3d156145e3573d906145c982613173565b916145d76040519384613151565b82523d6000602084013e565b606090565b9290803b1561477257614652916020916001600160a01b0394604051809581948293897f150b7a02000000000000000000000000000000000000000000000000000000009b8c86523360048701521660248501526044840152608060648401526084830190613014565b03916000968791165af190829082614711575b50506146eb576146736145b8565b805190816146e65760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608490fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b909192506020813d60201161476a575b8161472e60209383613151565b81010312610a225751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106285750903880614665565b3d9150614721565b50505050600190565b670de0b6b3a764000091600019838309928083029283808610950394808603951461483757828510156147fb57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614845570490565b634e487b7160e01b600052601260045260246000fd5b909190600019838209838202918280831092039180830392146148f957670de0b6b3a764000090818310156148c257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9192901561496b575081511561491e575090565b3b156149275790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501561497e5750805190602001fd5b6105969060405191829162461bcd60e51b835260206004840152602483019061301456fea164736f6c6343000817000a"; + hex"60a034620003e757601f196001600160401b03601f62004cd43881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516148b1908162000423823960805181613aba0152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146130d15750806306fdde031461300d578063081812fc14612fee578063095ea7b314612ef55780631400ecec14612e555780631c1cdd4c14612df05780631e99d56914612dd257806323b872dd14612dba57806339a73c0314612d7957806340e58ee514612b05578063425d30dd14612ab457806342842e0e14612a6457806342966c681461288957806344267570146128625780634857501f146127ec5780634869e12d146127b15780634cc55e111461233357806353b15727146122145780635fe3b567146121ed5780636352211e146121bd5780636d0cee75146121bd57806370a082311461214d57806375829def146120ba578063780a82c81461206d5780637cad6cd114611f9c5780637de6b1db14611d755780638659c27014611a26578063894e9a0d146117375780638bad38dd146116ba5780638f69b9931461161e5780639067b677146115ce57806395d89b41146114bf578063a22cb46514611402578063a6202bf214611305578063a80fc071146112b3578063ab167ccc14611164578063ad35efd414611102578063b2564569146110b1578063b88d4fde14611024578063b8a3be6614610fef578063b971302a14610fa0578063bc063e1a14610f7d578063bc2be1be14610f2d578063c156a11d14610a91578063c87b56dd14610975578063cc364f48146108aa578063d4dbd20b14610858578063d511609f1461080c578063d975dfed146107c0578063e985e9c51461076b578063ea5ead1914610743578063eac8f5b8146106f1578063f590c1761461068f578063f851a440146106695763fdd46d601461027e57600080fd5b34610666576060366003190112610666576004359061029b613200565b916102a461335d565b926102ad613ab0565b818352600b9360209185835260ff600160408720015460a81c161561064f5783855285835260ff600160408720015460a01c16610637576001600160a01b039182821692831561060d576001600160801b03938483169081156105f557878952600587528260408a2054169283821415806105e5575b6105c1576103308961437b565b878116841161058f575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610364916143a6565b858d5284845260408d20600201906103979082906001600160801b036001600160801b031983549260801b169116179055565b6103a090613654565b908084830151169181808251169160400151166103bc91613397565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610560575b848c528252600160408c2001541694610401818a886142ef565b604051908152a48033141580610556575b6104e8575b8333141590816104dd575b816104d2575b5061045c575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104b6575b808061042e565b6104bf9061327c565b6104ca5782386104af565b8280fd5b8380fd5b905083141538610428565b843b15159150610422565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161053e575b5050610417565b6105479061327c565b610552578438610537565b8480fd5b50803b1515610412565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103e7565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105ef89613b0c565b15610323565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b50346106665780600319360112610666576001600160a01b036020915416604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da578160409160209352600b8352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760016040836001600160a01b039360209552600b855220015416604051908152f35b50346106665760403660031901126106665760043590610761613200565b916102a48161437b565b5034610666576040366003190112610666576107856131ea565b604061078f613200565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb60209161437b565b6001600160801b0360405191168152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408260029260209452600b845220015460801c604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760036040836001600160801b039360209552600b855220015416604051908152f35b5034610666576020908160031936011261066657600435916108ca613635565b50828252600b815260ff600160408420015460a81c161561095e576060928252600b815264ffffffffff9182604082205460a01c1692600c8352604081818420541692600b8552205460c81c169160405193610925856132ad565b8452830152604082015261095c60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043561099481613809565b50826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a85578093610a04575b5050610a006040519282849384528301906131c5565b0390f35b909192503d8082843e610a17818461331f565b8201918381840312610a815780519067ffffffffffffffff82116104ca570182601f82011215610a8157805191610a4d83613341565b93610a5b604051958661331f565b838552858484010111610666575090610a79918480850191016131a2565b9038806109ea565b5080fd5b604051903d90823e3d90fd5b503461066657604036600319011261066657600435610aae613200565b610ab6613ab0565b818352600b9060209082825260ff600160408720015460a81c161561064f57838552600582526001600160a01b03918260408720541693843303610f0e57610afd8661437b565b906001600160801b039081831680158015610b9d575b50505050505081811615610b855783610b2b9161396b565b90811680610b4b5760248460405190637e27328960e01b82526004820152fd5b8203610b55578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610ba5613ab0565b898b5282865260ff600160408d20015460a81c1615610ef757898b5282865260ff600160408d20015460a01c16610edf57881561060d57610ec757888a52600585528660408b205416918289141580610eb7575b610e9357610c068a61437b565b8481168311610e615750908a949392918a86528087526040862093610c70610c398760028d89541698015460801c6143a6565b8d8952838a52610c6b600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b613654565b90610c8c818a8401511692826040818351169201511690613397565b161115610e32575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cd38186886142ef565b604051908152a48033141580610e28575b610dbe575b813314159081610db3575b81610da8575b50610d37575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b13565b803b156104ca57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d90575b80610d00565b610d999061327c565b610da4578538610d8a565b8580fd5b905081141538610cfa565b823b15159150610cf4565b803b156104ce57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e14575b5050610ce9565b610e1d9061327c565b6104ce578338610e0d565b50803b1515610ce4565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c94565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ec18a613b0c565b15610bf9565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610666578060031936011261066657602060405167016345785d8a00008152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da576040826001600160a01b039260209452600b8452205416604051908152f35b50346106665760203660031901126106665760ff600160406020936004358152600b855220015460a81c166040519015158152f35b50346106665760803660031901126106665761103e6131ea565b611046613200565b906064359067ffffffffffffffff82116104ce57366023830112156104ce578160040135928461107585613341565b93611083604051958661331f565b8585523660248783010111610a8157856110ae9660246020930183880137850101526044359161369c565b80f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460b01c166040519015158152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5761113b906138e4565b60405190600581101561115057602092508152f35b602483634e487b7160e01b81526021600452fd5b5034610666576101403660031901126106665761117f613ab0565b611187613635565b9064ffffffffff8042168084528161119d613688565b16156112ac5781806111ad613688565b8301165b16602085015260e4359082821682036112a75701166040830152600435916001600160a01b03918284168094036112a757602435908382168092036112a757604435906001600160801b0382168092036112a757606435908582168092036106665750608435918215158093036112a75760a435938415158095036112a7576040519761123d89613290565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126112a7576040519161127783613303565b6101043591821682036112a7578261129f9260209452610124358482015260e0820152613b75565b604051908152f35b600080fd5b81836111b1565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760026040836001600160801b039360209552600b855220015416604051908152f35b50346106665760203660031901126106665761131f6131ea565b6001600160a01b03808354163381036113d9575081169081835260026020526001600160801b036040842054169081156113a85781611379918486526002602052604086206001600160801b0319815416905533906142ef565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106665760403660031901126106665761141c6131ea565b602435908115158092036112a7576001600160a01b031690811561148e5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657806003193601126106665760405190806004549160018360011c92600185169485156115c4575b60209586861081146115b05785885287949392918790821561158e575050600114611534575b50506115209250038361331f565b610a006040519282849384528301906131c5565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b85831061157657505061152093508201013880611512565b8054838901850152879450869390920191810161155e565b925093505061152094915060ff191682840152151560051b8201013880611512565b602483634e487b7160e01b81526022600452fd5b93607f16936114ec565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57611657906138e4565b906005821015908161169857600283149182156116ac575b8215611683575b6020836040519015158152f35b90915061169857506004602091143880611676565b80634e487b7160e01b602492526021600452fd5b50600383149150600061166f565b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d9575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b50346106665760203660031901126106665780610140604051611759816132c9565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152611795613635565b61012082015201526004358152600b60205260ff600160408320015460a81c1615611a0e576004358152600b60205260408120906118636002604051936117db856132e6565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613654565b6101208301526118746004356138e4565b60058110156119fa576101406101a093600264ffffffffff93146119ef575b6101208101518360406001600160a01b0360a085015116966004358152600c6020522054169084604084015116606084015115159661010085015115159160c086015115159060e08701511515926001600160a01b038851169a60808b60208b015116990151151590604051996119098b6132c9565b8d8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152610100840152610120830152828201526040519384528260208201511660208501526040810151151560408501526060810151151560608501526001600160a01b0360808201511660808501528260a08201511660a085015260c0810151151560c085015260e0810151151560e085015261010081015115156101008501526119e4610120820151610120860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b015116610180820152f35b836060820152611893565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461066657602080600319360112610a815760043567ffffffffffffffff81116104ca57611a5990369060040161324b565b9190611a63613ab0565b83925b808410611a71578480f35b611a7c84828461360f565b3593611a86613ab0565b848652600b80855260ff90600190828260408b20015460a81c1615611d5e57878952808752604089208281015460a01c841615611ad55760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d4657611b0681600052600b6020526001600160a01b0360406000205416331490565b15611d2657611b148161382c565b818a52828952611b29600260408c2001613654565b906001600160801b0395868351168783161015611d0e57838c52848b5260408c205460f01c1615611cf65791818a8c7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b9d878b85611b9360409b879f9e9d9b84905116613397565b9701511690613397565b85835286845287832098895490600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316178b5560038c84169b8c15611cdd575b019b87169b8c6001600160801b03198254161790556001600160a01b03808093169a8b96600589522054169889965260408d2001541694611c228b85886142ef565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611c86575b505050505050600101929190611a66565b813b15610da457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611cc9575b80808080611c75565b611cd29061327c565b610552578438611cc0565b828101600160a01b60ff60a01b19825416179055611be0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043590611d94613ab0565b818352600b815260ff600160408520015460a81c1615611f8557611db7826138e4565b6005811015611f715760048103611de05760248360405190634a5541ef60e01b82526004820152fd5b60038103611e00576024836040519063fe19f19f60e01b82526004820152fd5b600214611f5957611e2782600052600b6020526001600160a01b0360406000205416331490565b15611f3a57818352600b815260ff604084205460f01c1615611f2257818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b611eca575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104ca57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611f0e575b80611e9b565b611f179061327c565b6104ca578238611f08565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d95750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116120595760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600c8452205416604051908152f35b5034610666576020366003190112610666576120d46131ea565b9080546001600160a01b0380821693338503612126576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610666576020366003190112610666576001600160a01b0361216f6131ea565b16801561218c578160409160209352600683522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106665760203660031901126106665760206121dc600435613809565b6001600160a01b0360405191168152f35b503461066657806003193601126106665760206001600160a01b0360015416604051908152f35b5034610666576101603660031901126106665761222f613ab0565b6040519061223c82613290565b6122446131ea565b825261224e613200565b602083015261225b61335d565b60408301526001600160a01b039060643582811681036112a757606084015260843580151581036112a757608084015260a43580151581036112a75760a084015260603660c319011261066657506040516122b5816132ad565b64ffffffffff60c43581811681036112a757825260e43581811681036112a75760208301526101043590811681036112a757604082015260c08301526040610123193601126112a7576040519161230b83613303565b6101243591821682036112a7578261129f9260209452610144358482015260e0820152613b75565b50346106665760403660031901126106665767ffffffffffffffff6004358181116104ca5761236690369060040161324b565b90916024359081116104ce5761238090369060040161324b565b612388613ab0565b80830361277a57845b83811061239c578580f35b6123a781858761360f565b35906123b481868861360f565b35875260056020526001600160a01b036040882054166123d582858761360f565b35906001600160801b03821682036112a7576123ef613ab0565b838952600b60205260ff600160408b20015460a81c161561064f57838952600b60205260ff600160408b20015460a01c1661063757801561060d576001600160801b038216156127625783895260056020526001600160a01b0360408a205416918282141580612752575b61272e576124678561437b565b6001600160801b0381166001600160801b038316116126fe575090899291858452600b60205260408420926124e66001600160a01b0385541694610c6b6124b68560028094015460801c6143a6565b918a8952600b60205260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361250a8160208401511692826040818351169201511690613397565b1611156126cd575b868552600b6020526001600160a01b0360016040872001541661253f6001600160801b03841685836142ef565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126c3575b612659575b83331415908161264e575b81612643575b506125d1575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612391565b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161262b575b808061259a565b6126349061327c565b61263f578638612624565b8680fd5b905083141538612594565b843b1515915061258e565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af16126af575b5050612583565b6126b89061327c565b6105525784386126a8565b50803b151561257e565b868552600b6020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612512565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061275c85613b0c565b1561245a565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb6020916143c1565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f855780612827836138e4565b9260058410156119fa57600260209403612848575b50506040519015158152f35b8152600b8352604090205460f01c60ff169050388061283c565b503461066657806003193601126106665760206001600160a01b03600a5416604051908152f35b503461066657602080600319360112610a8157600435906128a8613ab0565b818352600b815260ff600160408520015460a81c1615611f8557818352600b815260ff600160408520015460a01c1615612a33576128e582613b0c565b15611f3a5781600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c16159081612a29575b5080612a21575b612a09577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260058352604060002054169182159283156129ce575b846000526005825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129b6575080f35b60249060405190637e27328960e01b82526004820152fd5b6129ef85600052600760205260406000206001600160a01b03198154169055565b806000526006825260406000206000198154019055612964565b60248360405190630da9b01360e01b82526004820152fd5b506000612924565b905015153861291d565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657612a7336613216565b60405191602083019383851067ffffffffffffffff861117612a9e576110ae9460405285845261369c565b634e487b7160e01b600052604160045260246000fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460a01c166040519015158152f35b503461066657602090816003193601126106665760043590612b25613ab0565b818152600b9283815260ff600160408420015460a81c161561095e5782825283815260408220600181015460a01c60ff1615612b735760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611d4657612b9e81600052600b6020526001600160a01b0360406000205416331490565b15611d2657612bac8161382c565b93818452808352612bc260026040862001613654565b916001600160801b0393848451168588161015611f595781865282815260ff604087205460f01c1615611f2257612c06878683611b938a9b838a9c9b9c5116613397565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d5f575b01988716988981546001600160801b0319161790556001600160a01b038096168097600585528760408b205416978893865260408b20600101541693612c928c84876142ef565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612d0e578480f35b823b15610552576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d50575b81818080808480f35b612d599061327c565b81612d47565b60018101600160a01b60ff60a01b19825416179055612c4b565b5034610666576020366003190112610666576001600160801b0360406020926001600160a01b03612da86131ea565b16815260028452205416604051908152f35b5034610666576110ae612dcc36613216565b916133c6565b50346106665780600319360112610666576020600954604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57612e29906138e4565b9060058210156116985760208215838115612e4a575b506040519015158152f35b600191501482612e3f565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f8557602091604082828152600b85522060ff815460f01c1680612ee3575b612eba575b50506001600160801b0360405191168152f35b612edc92506001600160801b036002612ed6920154169161382c565b90613397565b3880612ea7565b5060ff600182015460a01c1615612ea2565b503461066657604036600319011261066657612f0f6131ea565b602435612f1b81613809565b33151580612fdb575b80612fb1575b612f815781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600760205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260086020526040842033855260205260ff60408520541615612f2a565b50336001600160a01b0382161415612f24565b50346106665760203660031901126106665760206121dc600435613373565b503461066657806003193601126106665760405190806003549160018360011c92600185169485156130c7575b60209586861081146115b05785885287949392918790821561158e57505060011461306d5750506115209250038361331f565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8583106130af57505061152093508201013880611512565b80548389018501528794508693909201918101613097565b93607f169361303a565b905034610a81576020366003190112610a81576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104ca57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613178575b811561314e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613147565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613140565b60005b8381106131b55750506000910152565b81810151838201526020016131a5565b906020916131de815180928185528580860191016131a2565b601f01601f1916010190565b600435906001600160a01b03821682036112a757565b602435906001600160a01b03821682036112a757565b60609060031901126112a7576001600160a01b039060043582811681036112a7579160243590811681036112a7579060443590565b9181601f840112156112a75782359167ffffffffffffffff83116112a7576020808501948460051b0101116112a757565b67ffffffffffffffff8111612a9e57604052565b610100810190811067ffffffffffffffff821117612a9e57604052565b6060810190811067ffffffffffffffff821117612a9e57604052565b610160810190811067ffffffffffffffff821117612a9e57604052565b610140810190811067ffffffffffffffff821117612a9e57604052565b6040810190811067ffffffffffffffff821117612a9e57604052565b90601f8019910116810190811067ffffffffffffffff821117612a9e57604052565b67ffffffffffffffff8111612a9e57601f01601f191660200190565b604435906001600160801b03821682036112a757565b61337c81613809565b5060005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116133b057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156135f75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c161590816135ed575b50806135e5575b6135ce57868552600581528284862054169487331515938461351e575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876134e6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036134b85750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61350782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055613454565b9192938091509061358d575b15613538579087839261342b565b848887613555576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156135b2575b8061352a575087825260078352338486842054161461352a565b5085825260088352848220338352835260ff8583205416613598565b602487855190630da9b01360e01b82526004820152fd5b50600161340e565b9050151538613407565b6024604051633250574960e11b815260006004820152fd5b919081101561361f5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190613642826132ad565b60006040838281528260208201520152565b90604051613661816132ad565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112a75790565b91906136a98282856133c6565b803b6136b6575b50505050565b6137126001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906131c5565b03906020816000938185885af1908290826137a8575b505061375f578261373761434b565b80519190826137585760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036137905750388080806136b0565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613801575b816137c56020938361331f565b81010312610a815751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106665750903880613728565b3d91506137b8565b8060005260056020526001600160a01b03604060002054169081156129b6575090565b600090808252600c60205264ffffffffff918260408220541642106138de57600b6020526040812092835490808260c81c1691824210156138c85761387d9394955060a01c16809103904203614682565b90828152600b6020526001600160801b03926138a3846002604085200154168094614762565b9283116138b05750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b80600052600b602052604060002060ff600182015460a01c1660001461390b575050600490565b805460f81c613964575460a01c64ffffffffff16421061395e5761392e8161382c565b90600052600b6020526001600160801b03806002604060002001541691161060001461395957600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613aa6575b5080613a9b575b613a84579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613a4c575b169283613a36575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613a12565b613a6d86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613a0a565b602486885190630da9b01360e01b82526004820152fd5b5081811615156139a9565b90501515386139a2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ae257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b038060408420541692833314938415613b51575b50508215613b3f57505090565b909150613b4c3392613373565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613b32565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156142e3576000906142af575b613bf691506001600160801b0360408501511690602060e086015101519161443c565b916001600160801b0383511660c082015190156142855764ffffffffff8151161561425b5764ffffffffff81511690604081019164ffffffffff835116908181101561421b57505064ffffffffff60208201511680151580614209575b6141c75750602064ffffffffff9101511664ffffffffff825116908181101561418757505064ffffffffff8042169151169081811015614147575050600954926001600160801b0381511660405190613cab826132ad565b815260006020820152600060408201526001600160a01b0360608401511660c08401519064ffffffffff604083015116608086015115159060a087015115159064ffffffffff6001600160a01b038951169551169060405195613d0d876132e6565b8652602086019182526040860190815260608601938452608086016000815260a0870195865260c08701946000865260e08801936001855261010089019586526101208901998a528d600052600b6020527fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff00000000000000000000000000000000000000006001600160a01b0360406000209d5116945160a01b16965160c81b169351151560f01b169351151560f81b16931717171785556001600160a01b03600186019451167fffffffffffffffffff000000000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000075ff00000000000000000000000000000000000000000074ff000000000000000000000000000000000000000088549751151560a01b169451151560a81b169451151560b01b1694161717171790556001600160801b036040600360028401945193613ef484865116966001600160801b03199788825416178155856020880151166001600160801b036001600160801b031983549260801b169116179055565b01920151168282541617905564ffffffffff602060c085015101511680614129575b50600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b0360208301511680156135f757613f90856001600160a01b039261396b565b166140f857613fc56001600160a01b036060840151166001600160801b0380845116816020860151160116903090339061457b565b6001600160801b03604082015116806140c9575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140c06001600160a01b03606089015116976080810151151560a082015115159061408a6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b6140f2906001600160a01b036060850151166001600160a01b0360e0860151511690339061457b565b38613fd9565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600c60205260406000209064ffffffffff1982541617905538613f16565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b81516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508064ffffffffff8351161015613c53565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116142db575b816142c96020938361331f565b810103126112a757613bf69051613bd3565b3d91506142bc565b6040513d6000823e3d90fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526143499161434460648361331f565b6145e6565b565b3d15614376573d9061435c82613341565b9161436a604051938461331f565b82523d6000602084013e565b606090565b6143a390614388816143c1565b90600052600b60205260026040600020015460801c90613397565b90565b9190916001600160801b03808094169116019182116133b057565b80600052600b6020526143da6002604060002001613654565b81600052600b602052604060002060ff600182015460a01c1660001461440d57506001600160801b039150602001511690565b5460f81c61441f57506143a39061382c565b6143a391506001600160801b036040818351169201511690613397565b909291614447613635565b936001600160801b03928381169182156145535767016345785d8a000080821161451c578085116144e5575061449185614482819386614762565b16946020890195865284614762565b1691846144a86040890194808652828751166143a6565b1610156144cf576144c18491826144ca95511690613397565b91511690613397565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614566816132ad565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612a9e57614349926040525b6001600160a01b031690614611600080836020829551910182875af161460a61434b565b9084614811565b90815191821515928361465a575b5050506146295750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a81576020015190811591821503610666575038808061461f565b670de0b6b3a764000091600019838309928083029283808610950394808603951461473e578285101561470257908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b50508092501561474c570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461480057670de0b6b3a764000090818310156147c957947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614850575080511561482657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061489b575b614861575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561485956fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"6080806040523461001757615dcc90816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346142f85760403660031901126142f8576001600160a01b0360043516600435036142f857610056608061486e565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614946565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916147dd575b506001600160a01b03610117911680608052614b39565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614305576fffffffffffffffffffffffffffffffff916000916147be575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561430557600090614781575b6101e59150614c86565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561430557600091614752575b5060c0516fffffffffffffffffffffffffffffffff16801561473c576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614d82565b610120608001526040514660208201526bffffffffffffffffffffffff1960043560601b16604082015260243560548201526054815280608081011067ffffffffffffffff60808301111761431157608081016040526020815191012061041a602963ffffffff61032e6103078261016861ffff8860101c1606166155e2565b91601e604660ff6103248460146050848d60081c160601166155e2565b98160601166155e2565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261036e815180926020602488019101614826565b83017f2c0000000000000000000000000000000000000000000000000000000000000060248201526103aa825180936020602585019101614826565b017f252c00000000000000000000000000000000000000000000000000000000000060258201526103e5825180936020602785019101614826565b017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826148df565b6104526fffffffffffffffffffffffffffffffff6040608001511660ff61044b6001600160a01b0360805116614f69565b16906150d2565b6104666001600160a01b0360805116614946565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143055760249160009161471d575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa801561430557610528926000916146ee575b5064ffffffffff809116911661541d565b61012051610180519092916105b2602161054f60646105488187066158c3565b95046155e2565b6040519481610568879351809260208087019101614826565b820161057d8251809360208085019101614826565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836148df565b610100608001519260c060800151956101206080015197604051996105d68b61486e565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106a660c08401518451906159cf565b906109b361015c604051926106ba846148c3565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526107236040516106f38161488b565b60009052855160208701207fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4701490565b156146e6576090945b610735866155e2565b916040519586938493661e339034b21e9160c91b60208601526109818351958692610767846027840160208901614826565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107ae8551809660206042888701019101614826565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108b491889160f990910190602001614826565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094f91899161015190910190602001614826565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614826565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826148df565b6101008301526101208201526028610100830151604051906109d48261488b565b60008252610c7a61015c604051926109eb846148c3565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b610a2782615d49565b808211156146de5750945b610a3d8787016155e2565b91604051958693661e339034b21e9160c91b60208601528151610a67816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610aaa825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ba682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c3582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610c5c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101845201826148df565b610160840152016101808201526028602083015160405190610c9b8261488b565b60008252610ce561015c60405192610cb2846148c3565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a1e84615ccb565b835201602082015261102060808301516030604051610d038161488b565b60008152610faa61015c60405194610d1a866148c3565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d4d86615ccb565b610d5682615d49565b808211156146d65750935b610d6d602886016155e2565b91604051978893661e339034b21e9160c91b60208601528151610d97816027880160208601614826565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dda825180936020604285019101614826565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ed682518093602060f985019101614826565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f6582518093602061015185019101614826565b01661e17ba32bc3a1f60c91b610151820152610f8c82518093602061015885019101614826565b01631e17b39f60e11b6101588201520361013c8101865201846148df565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615068565b6060820152604051908161010081011067ffffffffffffffff6101008401111761431157610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161010084015191606081015194604051611176816148a7565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051966111d38861486e565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614311576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761431157611cb1611d129160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611868615996565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d0d60d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161199a60b88660208501936118da81605e840187614826565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261193f825180936020609385019101614826565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866148df565b6119a2615996565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a0881606b8a0184614826565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a4d825180936020608e85019101614826565b019082608e830152611a9160a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896148df565b611bd7610108611a9f615996565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b2b815180926020607387019101614826565b8201908760738301526076820152875190611b4a826096830188614826565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6148df565b611bdf615996565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614826565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cf382518093602060c485019101614826565b019160c483015260c78201520360b88101875201856148df565b615068565b92611d32611d1e614c14565b896020815191012090602081519101201490565b9788156146ad575b506040518060c081011067ffffffffffffffff60c0830111176143115760c08101604052609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614311576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146144885760405161218c8161488b565b60008152995b1561432757604051806101e081011067ffffffffffffffff6101e083011117614311576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761431157613b9f9c612e5a6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f2b9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612df68151809260208a8c019101614826565b8701612e0b8251809360208a85019101614826565b01612e1f8251809360208985019101614826565b01612e338251809360208885019101614826565b01612e478251809360208785019101614826565b01918201520360168101865201846148df565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e9f6026998260208c9451948593019101614826565b8901612eb48251809360208c85019101614826565b01612ec88251809360208b85019101614826565b01612edc8251809360208a85019101614826565b01612ef08251809360208985019101614826565b01612f048251809360208885019101614826565b01612f188251809360208785019101614826565b019182015203600d8101895201876148df565b6137be604c60e08301516101208401519361351a61314d6060604084015193015196612f578186615c0f565b9461314861012b604051612f6a816148c3565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fd4815180926020603787019101614826565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015282519261311891849161012090910190602001614826565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876148df565b615c0f565b9561332c61012b604051613160816148c3565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131ca815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261330782518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886148df565b6133368184615c77565b9261351561012b604051613349816148c3565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526133b3815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134f082518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856148df565b615c77565b906136f961012b60405161352d816148c3565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613597815180926020603787019101614826565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136d482518093602061012085019101614826565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836148df565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261375f815180926020604589019101614826565b8401613775825180936020604585019101614826565b0161378a825180936020604585019101614826565b0161379f825180936020604585019101614826565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826148df565b613a9e61019a6101408401516101a0850151906137ff6137f96137f36137ed60e060408b01519a0151946155e2565b946155e2565b976155e2565b916155e2565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061399a815180926020858a019101614826565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d2200000000000000000061013288015261014996613a048251809360208b85019101614826565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a478251809360208985019101614826565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a8a8251809360208785019101614826565b01918201520361017a8101855201836148df565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b2a815180926020607b89019101614826565b8401613b40825180936020607b85019101614826565b01613b55825180936020607b85019101614826565b01613b6a825180936020607b85019101614826565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826148df565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614305576000916142ba575b6142b661424f614154614245609487613d3b6089613c198a614946565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613c60815180926020604088019101614826565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613cc5825180936020606385019101614826565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d06825180936020608685019101614826565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826148df565b6101a05160a05161403e61017e613d536024356155e2565b9360a060800151613d6e6001600160a01b0360805116614946565b90604051968793613f2b60208601987f54686973204e465420726570726573656e74732061207061796d656e742073748a527f7265616d20696e2061205361626c696572205632200000000000000000000000604088015282516020840190613ddb8160558b0184614826565b8801947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613e658260b183018a614826565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ea082518093602060c385019101614826565b01613ed97f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614826565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613f1782518093602060d185019101614826565b019260d184015251809360d5840190614826565b019060d5820152613f4682518093602060df85019101614826565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560e38201527f204e4654206d616b657320746865206e6577206f776e657220746865207265636101038201527f697069656e74206f66207468652073747265616d2e205468652066756e6473206101238201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e206101438201527f666f72207468652070726576696f757320726563697069656e742e00000000006101638201520361015e8101855201836148df565b6101a051906141af6140516024356155e2565b916140d0602d604051809560208201976a029b0b13634b2b9102b19160ad1b8952614086815180926020602b87019101614826565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140c18251809360208785019101614826565b0103600d8101865201846148df565b610160516140dd90615733565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a015261411e815180926020602e8d019101614826565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614826565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614826565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614210825180936020609285019101614826565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826148df565b60e0819052615733565b6142a2603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142928151809260208686019101614826565b810103601d8101845201826148df565b604051918291602083526020830190614849565b0390f35b90506020813d6020116142fd575b816142d5602093836148df565b810103126142f85751906001600160a01b03821682036142f85790614154613bfc565b600080fd5b3d91506142c8565b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761431157610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123df565b604051806101c081011067ffffffffffffffff6101c083011117614311576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612192565b6146cf9198506146bb614c4d565b906020815191012090602081519101201490565b9638611d3a565b905093610d61565b905094610a32565b60d09461072c565b614710915060203d602011614716575b61470881836148df565b810190614929565b38610517565b503d6146fe565b614736915060203d6020116147165761470881836148df565b386104c1565b634e487b7160e01b600052601260045260246000fd5b614774915060203d60201161477a575b61476c81836148df565b810190614901565b3861023f565b503d614762565b506020813d6020116147b6575b8161479b602093836148df565b810103126142f8575160058110156142f8576101e5906101db565b3d915061478e565b6147d7915060203d60201161477a5761476c81836148df565b38610181565b90506020813d60201161481e575b816147f8602093836148df565b810103126142f857516001600160a01b03811681036142f8576001600160a01b03610100565b3d91506147eb565b60005b8381106148395750506000910152565b8181015183820152602001614829565b9060209161486281518092818552858086019101614826565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761431157604052565b6020810190811067ffffffffffffffff82111761431157604052565b6060810190811067ffffffffffffffff82111761431157604052565b6040810190811067ffffffffffffffff82111761431157604052565b90601f8019910116810190811067ffffffffffffffff82111761431157604052565b908160209103126142f857516fffffffffffffffffffffffffffffffff811681036142f85790565b908160209103126142f8575164ffffffffff811681036142f85790565b6001600160a01b03166040519061495c826148a7565b602a8252602082016040368237825115614a755760309053815160019060011015614a7557607860218401536029905b8082116149fa57505061499c5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b9091600f81166010811015614a60577f3031323334353637383961626364656600000000000000000000000000000000901a614a3684866158b2565b5360041c918015614a4b57600019019061498c565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161431157601f01601f191660200190565b3d15614ad2573d90614ab882614a8b565b91614ac660405193846148df565b82523d6000602084013e565b606090565b6020818303126142f85780519067ffffffffffffffff82116142f8570181601f820112156142f8578051614b0a81614a8b565b92614b1860405194856148df565b818452602082840101116142f857614b369160208085019101614826565b90565b6000809160405160208101906395d89b4160e01b825260048152614b5c816148c3565b51915afa614b68614aa7565b90158015614c08575b614bce5780602080614b8893518301019101614ad7565b601e815111600014614b365750604051614ba1816148c3565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614bdb816148c3565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b71565b60405190614c21826148c3565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614c5a826148c3565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614d6c5760048103614ca05750614b36614c4d565b60038103614ce25750604051614cb5816148c3565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d245750604051614cf7816148c3565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d3357614b36614c14565b604051614d3f816148c3565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660409081516395d89b4160e01b8152600081600481855afa908115614f5e57600091614f3b575b50614e178351614dc1816148c3565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020918201528251908301207fc66b376a19264d832c1bc254000c18944ca5aa57ed50f4ea637c4da424d4c3bb1490565b15614e5557505051614e28816148c3565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b614eb98351614e63816148c3565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020918201528251908301207f6ab655856fa5352de8c05542b1937ac63c59342da992602767c02734cc5391651490565b15614ef757505051614eca816148c3565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b614f379083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614849565b0390fd5b614f5891503d806000833e614f5081836148df565b810190614ad7565b38614db2565b83513d6000823e3d90fd5b60405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614fa1816148c3565b6000928392839251915afa614fb4614aa7565b9080614feb575b15614fe757602081805181010312614fe357602001519060ff82168203614fe0575090565b80fd5b5080fd5b5090565b506020815114614fbb565b60405190615003826148c3565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061503c826148c3565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906150d092949360405195869260209461508a81518092888089019101614826565b840161509e82518093888085019101614826565b016150b182518093878085019101614826565b016150c482518093868085019101614826565b010380855201836148df565b565b80156153e257600091806153bd575090505b600190808281101561514e575050506150fb61502f565b614b36602260405183615118829551809260208086019101614826565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826148df565b66038d7ea4c6800011156153605760409081519060a0820182811067ffffffffffffffff821117614311578084526151858161488b565b600081528252825190615197826148c3565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516151d1816148c3565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615208816148c3565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615240816148c3565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615334575b50845194615287866148c3565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b8281106153215750505050615302615308917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526152fd866148c3565b6155e2565b916158c3565b916005851015614a7557614b369460051b015192615068565b81810184015188820185015283016152b8565b9591926103e89081851061535757508680916064600a8704069504930196615275565b9392965061527a565b505061536a614ff6565b614b36602860405183615387829551809260208086019101614826565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826148df565b600a0a9182156153ce5750046150e4565b80634e487b7160e01b602492526012600452fd5b50506040516153f0816148c3565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b6201518091030480615485575061543261502f565b614b3660266040518361544f829551809260208086019101614826565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826148df565b61270f8111615554576001810361551157614b3660206154d96040516154aa816148c3565b600481527f204461790000000000000000000000000000000000000000000000000000000083820152936155e2565b60405193816154f18693518092868087019101614826565b820161550582518093868085019101614826565b010380845201826148df565b614b3660206154d9604051615525816148c3565b600581527f204461797300000000000000000000000000000000000000000000000000000083820152936155e2565b5061555d614ff6565b614b36602a6040518361557a829551809260208086019101614826565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826148df565b906155ba82614a8b565b6155c760405191826148df565b82815280926155d8601f1991614a8b565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615725575b506d04ee2d6d415b85acef810000000080831015615716575b50662386f26fc1000080831015615707575b506305f5e100808310156156f8575b50612710808310156156e9575b5060648210156156d9575b600a809210156156cf575b60019081602161567a600187016155b0565b95860101905b61568c575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156156ca57919082615680565b615685565b9160010191615668565b919060646002910491019161565d565b60049193920491019138615652565b60089193920491019138615645565b60109193920491019138615636565b60209193920491019138615624565b60409350810491503861560b565b80511561589e57604051615746816148a7565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116158885760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103615888576157e5906002959492951b6155b0565b936020850193839284518501935b84811061583557505050505060039051068060011461582257600214615817575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c1688010151888501531685010151868201530195939291906157f3565b634e487b7160e01b600052601160045260246000fd5b506040516158ab8161488b565b6000815290565b908151811015614a75570160200190565b806158d557506040516158ab8161488b565b600a81101561593a576158e7906155e2565b614b36602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261592a8151809260208686019101614826565b81010360028101845201826148df565b615943906155e2565b614b36602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159868151809260208686019101614826565b81010360018101845201826148df565b604051906159a3826148c3565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615c01576159dd615996565b9061271090810390811161588857614b36916159fb610136926155e2565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615a87815180926020605788019101614826565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615b0f82518093602060a785019101614826565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615b7082518093602060d585019101614826565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826148df565b50506040516158ab8161488b565b60306150d0919392936040519481615c31879351809260208087019101614826565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615c688251809360208785019101614826565b010360108101855201836148df565b60256150d0919392936040519481615c99879351809260208087019101614826565b820164010714051160dd1b6020820152615cbc8251809360208785019101614826565b010360058101855201836148df565b60009080518015615d4157906000916000915b818310615cf057505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615d2387856158b2565b511614615d39575b600d01936001019190615cde565b849350615d2b565b505050600090565b60009080518015615d4157906000916000915b818310615d6e5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615da187856158b2565b511614615db7575b601001936001019190615d5c565b849350615da956fea164736f6c6343000817000a"; + hex"6080806040523461001757615ea390816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661568d565b91601e604660ff61030b8460146050848d60081c1606011661568d565b981606011661568d565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615014565b169061517d565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff80911691166154c8565b610120516101805190929161059d602161053a606461053381870661599a565b950461568d565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615aa6565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b600081528661596e565b156147c9576090945b6106fa8661568d565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615da2565b6109ec82615e20565b808211156147c15750945b610a0287870161568d565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615da2565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615da2565b610d1b82615e20565b808211156147b95750935b610d326028860161568d565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615113565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615a6d565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615a6d565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615a6d565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615a6d565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615113565b92611ce9611ce3614d0b565b8961596e565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615ce6565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615ce6565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615d4e565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615d4e565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461568d565b9461568d565b9761568d565b9161568d565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561568d565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561568d565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b61016051614104906157de565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e08190526157de565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b9061596e565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d848761595d565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660409081516395d89b4160e01b8152600081600481855afa90811561500957600091614fe6575b50614ee88351614eb8816149de565b601181527f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000060208201528261596e565b15614f2657505051614ef9816149de565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b614f648351614f34816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000060208201528261596e565b15614fa257505051614f75816149de565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b614fe29083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61500391503d806000833e614ffb81836149fa565b810190614bce565b38614ea9565b83513d6000823e3d90fd5b60405160208101907f313ce5670000000000000000000000000000000000000000000000000000000082526004815261504c816149de565b6000928392839251915afa61505f614b9e565b9080615096575b156150925760208180518101031261508e57602001519060ff8216820361508b575090565b80fd5b5080fd5b5090565b506020815114615066565b604051906150ae826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b604051906150e7826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b9061517b92949360405195869260209461513581518092888089019101614909565b840161514982518093888085019101614909565b0161515c82518093878085019101614909565b0161516f82518093868085019101614909565b010380855201836149fa565b565b801561548d5760009180615468575090505b60019080828110156151f9575050506151a66150da565b614c2d6022604051836151c3829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c68000111561540b5760409081519060a0820182811067ffffffffffffffff821117614402578084526152308161498a565b600081528252825190615242826149de565b8482526020917f4b000000000000000000000000000000000000000000000000000000000000008382015282840152835161527c816149de565b8581527f4d00000000000000000000000000000000000000000000000000000000000000838201528484015283516152b3816149de565b8581527f420000000000000000000000000000000000000000000000000000000000000083820152606084015283516152eb816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b6153df575b50845194615332866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b8281106153cc57505050506153ad6153b3917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526153a8866149de565b61568d565b9161599a565b916005851015614b6c57614c2d9460051b015192615113565b8181018401518882018501528301615363565b9591926103e89081851061540257508680916064600a8704069504930196615320565b93929650615325565b50506154156150a1565b614c2d602860405183615432829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a91821561547957500461518f565b80634e487b7160e01b602492526012600452fd5b505060405161549b816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061553057506154dd6150da565b614c2d6026604051836154fa829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f81116155ff57600181036155bc57614c2d6020615584604051615555816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361568d565b604051938161559c8693518092868087019101614909565b82016155b082518093868085019101614909565b010380845201826149fa565b614c2d60206155846040516155d0816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361568d565b506156086150a1565b614c2d602a60405183615625829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b9061566582614b82565b61567260405191826149fa565b8281528092615683601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000808210156157d0575b506d04ee2d6d415b85acef8100000000808310156157c1575b50662386f26fc10000808310156157b2575b506305f5e100808310156157a3575b5061271080831015615794575b506064821015615784575b600a8092101561577a575b6001908160216157256001870161565b565b95860101905b615737575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157755791908261572b565b615730565b9160010191615713565b9190606460029104910191615708565b600491939204910191386156fd565b600891939204910191386156f0565b601091939204910191386156e1565b602091939204910191386156cf565b6040935081049150386156b6565b805115615949576040516157f1816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159335760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116810361593357615890906002959492951b61565b565b936020850193839284518501935b8481106158e05750505050506003905106806001146158cd576002146158c2575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061589e565b634e487b7160e01b600052601160045260246000fd5b506040516159568161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615984575050505090565b6020929394508201209201201438808080615730565b806159ac57506040516159568161498a565b600a811015615a11576159be9061568d565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a018151809260208686019101614909565b81010360028101845201826149fa565b615a1a9061568d565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a5d8151809260208686019101614909565b81010360018101845201826149fa565b60405190615a7a826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cd857615ab4615a6d565b9061271090810390811161593357614c2d91615ad26101369261568d565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615b5e815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615be682518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615c4782518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159568161498a565b603061517b919392936040519481615d08879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615d3f8251809360208785019101614909565b010360108101855201836149fa565b602561517b919392936040519481615d70879351809260208087019101614909565b820164010714051160dd1b6020820152615d938251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e1857906000916000915b818310615dc757505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615dfa878561595d565b511614615e10575b600d01936001019190615db5565b849350615e02565b505050600090565b60009080518015615e1857906000916000915b818310615e455750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e78878561595d565b511614615e8e575b601001936001019190615e33565b849350615e8056fea164736f6c6343000817000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS From 9194e814796c01f2f6b4cb56c515fb833224b38e Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 5 Mar 2024 21:42:58 +0000 Subject: [PATCH 049/132] fix: update the count of inherited components (#831) --- src/SablierV2LockupDynamic.sol | 2 +- src/SablierV2LockupLinear.sol | 2 +- src/abstracts/SablierV2Lockup.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 197c3c78d..20ea00197 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -37,7 +37,7 @@ import { Lockup, LockupDynamic } from "./types/DataTypes.sol"; /// @title SablierV2LockupDynamic /// @notice See the documentation in {ISablierV2LockupDynamic}. contract SablierV2LockupDynamic is - ISablierV2LockupDynamic, // 1 inherited component + ISablierV2LockupDynamic, // 6 inherited components SablierV2Lockup // 14 inherited components { using CastingUint128 for uint128; diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 6a89afdd8..453451578 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -35,7 +35,7 @@ import { Lockup, LockupLinear } from "./types/DataTypes.sol"; /// @title SablierV2LockupLinear /// @notice See the documentation in {ISablierV2LockupLinear}. contract SablierV2LockupLinear is - ISablierV2LockupLinear, // 5 inherited components + ISablierV2LockupLinear, // 6 inherited components SablierV2Lockup // 14 inherited components { using SafeERC20 for IERC20; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 7da2fd231..24993f5ec 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -21,7 +21,7 @@ import { SablierV2Base } from "./SablierV2Base.sol"; abstract contract SablierV2Lockup is IERC4906, // 2 inherited components SablierV2Base, // 4 inherited components - ISablierV2Lockup, // 4 inherited components + ISablierV2Lockup, // 5 inherited components ERC721 // 6 inherited components { using SafeERC20 for IERC20; From 5ebdb03732e1ae5bf033f61b23423ef2db2e8fe6 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 6 Mar 2024 12:53:36 +0200 Subject: [PATCH 050/132] feat: implement SablierV2LockupTranched contract feat: include tranched in mapSymbol in NFTDescriptor docs: specify LockupTranched in README build: add SablierV2LockupTranched in shell scripts test: test SablierV2LockupTranched contract test: deploy core contracts in Base_Test test: use changePrank instead of vm.StartPrank test: update Precompiles bytecode --- README.md | 6 +- foundry.toml | 2 + shell/prepare-artifacts.sh | 2 + shell/update-precompiles.sh | 2 + src/SablierV2LockupDynamic.sol | 1 + src/SablierV2LockupLinear.sol | 1 + src/SablierV2LockupTranched.sol | 303 +++++++++++ src/SablierV2NFTDescriptor.sol | 2 + src/interfaces/ISablierV2LockupDynamic.sol | 11 +- src/interfaces/ISablierV2LockupLinear.sol | 3 +- src/interfaces/ISablierV2LockupTranched.sol | 131 +++++ src/libraries/Errors.sol | 29 +- src/libraries/Helpers.sol | 123 ++++- src/types/DataTypes.sol | 96 ++++ test/Base.t.sol | 72 ++- test/fork/Fork.t.sol | 5 +- test/fork/LockupDynamic.t.sol | 6 +- test/fork/LockupLinear.t.sol | 6 +- test/fork/LockupTranched.t.sol | 399 +++++++++++++++ test/fork/assets/DAI.t.sol | 3 + test/fork/assets/EURS.t.sol | 3 + test/fork/assets/SHIB.t.sol | 3 + test/fork/assets/USDC.t.sol | 3 + test/fork/assets/USDT.t.sol | 3 + test/integration/Integration.t.sol | 8 +- .../lockup-dynamic/LockupDynamic.t.sol | 17 +- .../concrete/lockup-dynamic/constructor.t.sol | 6 +- .../createWithDurations.t.sol | 2 +- .../createWithTimestamps.t.sol | 2 +- .../concrete/lockup-linear/LockupLinear.t.sol | 15 - .../lockup-tranched/LockupTranched.t.sol | 484 ++++++++++++++++++ .../lockup-tranched/constructor.t.sol | 45 ++ .../createWithDurations.t.sol | 195 +++++++ .../createWithDurations.tree | 23 + .../createWithTimestamps.t.sol | 407 +++++++++++++++ .../createWithTimestamps.tree | 58 +++ .../lockup-tranched/get-range/getRange.t.sol | 26 + .../lockup-tranched/get-range/getRange.tree | 5 + .../get-stream/getStream.t.sol | 45 ++ .../lockup-tranched/get-stream/getStream.tree | 8 + .../get-tranches/getTranches.t.sol | 26 + .../get-tranches/getTranches.tree | 5 + .../streamed-amount-of/streamedAmountOf.t.sol | 85 +++ .../streamed-amount-of/streamedAmountOf.tree | 11 + .../lockup-tranched/token-uri/tokenURI.t.sol | 65 +++ .../lockup-tranched/token-uri/tokenURI.tree | 5 + .../withdrawableAmountOf.t.sol | 77 +++ .../withdrawableAmountOf.tree | 9 + .../lockup/withdraw-hooks/withdrawHooks.t.sol | 284 ---------- .../lockup/withdraw-hooks/withdrawHooks.tree | 21 - .../concrete/lockup/withdraw/withdraw.t.sol | 14 +- .../lockup-dynamic/createWithTimestamps.t.sol | 2 +- .../fuzz/lockup-tranched/LockupTranched.t.sol | 127 +++++ .../lockup-tranched/createWithDurations.t.sol | 146 ++++++ .../createWithTimestamps.t.sol | 349 +++++++++++++ .../lockup-tranched/streamedAmountOf.t.sol | 148 ++++++ .../fuzz/lockup-tranched/withdraw.t.sol | 131 +++++ .../withdrawableAmountOf.t.sol | 111 ++++ .../shared/lockup-dynamic/LockupDynamic.t.sol | 15 - .../shared/lockup-linear/LockupLinear.t.sol | 15 - .../lockup-tranched/LockupTranched.t.sol | 159 ++++++ .../lockup-tranched/createWithDurations.t.sol | 28 + .../createWithTimestamps.t.sol | 68 +++ test/integration/shared/lockup/Lockup.t.sol | 14 - test/integration/shared/lockup/withdraw.t.sol | 8 - test/invariant/Invariant.t.sol | 5 +- test/invariant/LockupTranched.t.sol | 109 ++++ test/invariant/handlers/BaseHandler.sol | 3 +- test/invariant/handlers/LockupHandler.sol | 9 +- .../handlers/LockupTranchedCreateHandler.sol | 143 ++++++ .../handlers/LockupTranchedHandler.sol | 23 + test/unit/shared/Adminable.t.sol | 2 +- test/utils/Assertions.sol | 48 +- test/utils/BaseScript.t.sol | 6 +- test/utils/Calculations.sol | 33 +- test/utils/Defaults.sol | 86 +++- test/utils/DeployOptimized.sol | 24 +- test/utils/Events.sol | 20 +- test/utils/Fuzzers.sol | 162 +++++- test/utils/Precompiles.sol | 78 ++- test/utils/Precompiles.t.sol | 23 +- test/utils/Utils.sol | 23 +- 82 files changed, 4764 insertions(+), 517 deletions(-) create mode 100644 src/SablierV2LockupTranched.sol create mode 100644 src/interfaces/ISablierV2LockupTranched.sol create mode 100644 test/fork/LockupTranched.t.sol create mode 100644 test/integration/concrete/lockup-tranched/LockupTranched.t.sol create mode 100644 test/integration/concrete/lockup-tranched/constructor.t.sol create mode 100644 test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol create mode 100644 test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree create mode 100644 test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol create mode 100644 test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree create mode 100644 test/integration/concrete/lockup-tranched/get-range/getRange.t.sol create mode 100644 test/integration/concrete/lockup-tranched/get-range/getRange.tree create mode 100644 test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol create mode 100644 test/integration/concrete/lockup-tranched/get-stream/getStream.tree create mode 100644 test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol create mode 100644 test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree create mode 100644 test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol create mode 100644 test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree create mode 100644 test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol create mode 100644 test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree create mode 100644 test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol create mode 100644 test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree delete mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol delete mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree create mode 100644 test/integration/fuzz/lockup-tranched/LockupTranched.t.sol create mode 100644 test/integration/fuzz/lockup-tranched/createWithDurations.t.sol create mode 100644 test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol create mode 100644 test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol create mode 100644 test/integration/fuzz/lockup-tranched/withdraw.t.sol create mode 100644 test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol create mode 100644 test/integration/shared/lockup-tranched/LockupTranched.t.sol create mode 100644 test/integration/shared/lockup-tranched/createWithDurations.t.sol create mode 100644 test/integration/shared/lockup-tranched/createWithTimestamps.t.sol create mode 100644 test/invariant/LockupTranched.t.sol create mode 100644 test/invariant/handlers/LockupTranchedCreateHandler.sol create mode 100644 test/invariant/handlers/LockupTranchedHandler.sol diff --git a/README.md b/README.md index 55b3785f1..e8d7e4bf1 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,9 @@ contract MyContract { ## Architecture -V2 Core uses a singleton-style architecture, where all streams are managed in the `LockupLinear` and `LockupDynamic` -contracts. That is, Sablier does not deploy a new contract for each stream. It bundles all streams into a single -contract, which is more gas-efficient and easier to maintain. +V2 Core uses a singleton-style architecture, where all streams are managed in the `LockupLinear`, `LockupDynamic` and +`LockupTranched` contracts. That is, Sablier does not deploy a new contract for each stream. It bundles all streams into +a single contract, which is more gas-efficient and easier to maintain. For more information, see the [Technical Overview](https://docs.sablier.com/contracts/v2/reference/overview) in our docs, as well as these [diagrams](https://docs.sablier.com/contracts/v2/reference/diagrams). diff --git a/foundry.toml b/foundry.toml index 6d2d04a76..e93261086 100644 --- a/foundry.toml +++ b/foundry.toml @@ -8,6 +8,7 @@ "SablierV2Comptroller", "SablierV2LockupDynamic", "SablierV2LockupLinear", + "SablierV2LockupTranched", "SablierV2NFTDescriptor", ] optimizer = true @@ -68,6 +69,7 @@ [profile.smt.model_checker.contracts] "src/SablierV2LockupDynamic.sol" = ["SablierV2LockupDynamic"] "src/SablierV2LockupLinear.sol" = ["SablierV2LockupLinear"] + "src/SablierV2LockupTranched.sol" = ["SablierV2LockupTranched"] "src/SablierV2NFTDescriptor.sol" = ["SablierV2NFTDescriptor"] # Test the optimized contracts without re-compiling them diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index fc328f2fa..0d9d6a331 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -26,6 +26,7 @@ FOUNDRY_PROFILE=optimized forge build cp out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json $artifacts cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $artifacts cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $artifacts +cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $artifacts cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $artifacts interfaces=./artifacts/interfaces @@ -34,6 +35,7 @@ cp out-optimized/ISablierV2Comptroller.sol/ISablierV2Comptroller.json $interface cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $interfaces cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $interfaces cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $interfaces +cp out-optimized/ISablierV2LockupTranched.sol/ISablierV2LockupTranched.json $interfaces cp out-optimized/ISablierV2NFTDescriptor.sol/ISablierV2NFTDescriptor.json $interfaces erc20=./artifacts/interfaces/erc20 diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index dd2d205b0..cb0d51361 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -15,6 +15,7 @@ FOUNDRY_PROFILE=optimized forge build comptroller=$(cat out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json | jq -r '.bytecode.object' | cut -c 3-) lockup_dynamic=$(cat out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) +lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) nft_descriptor=$(cat out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) precompiles_path="test/utils/Precompiles.sol" @@ -27,6 +28,7 @@ fi sd "(BYTECODE_COMPTROLLER =)[^;]+;" "\$1 hex\"$comptroller\";" $precompiles_path sd "(BYTECODE_LOCKUP_DYNAMIC =)[^;]+;" "\$1 hex\"$lockup_dynamic\";" $precompiles_path sd "(BYTECODE_LOCKUP_LINEAR =)[^;]+;" "\$1 hex\"$lockup_linear\";" $precompiles_path +sd "(BYTECODE_LOCKUP_TRANCHED =)[^;]+;" "\$1 hex\"$lockup_tranched\";" $precompiles_path sd "(BYTECODE_NFT_DESCRIPTOR =)[^;]+;" "\$1 hex\"$nft_descriptor\";" $precompiles_path # Reformat the code with Forge diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 20ea00197..c4da4761d 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -110,6 +110,7 @@ contract SablierV2LockupDynamic is notNull(streamId) returns (LockupDynamic.StreamLD memory stream) { + // Retrieve the lockup stream from storage. Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 453451578..fff01f8e0 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -98,6 +98,7 @@ contract SablierV2LockupLinear is notNull(streamId) returns (LockupLinear.StreamLL memory stream) { + // Retrieve the lockup stream from storage. Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol new file mode 100644 index 000000000..dae58989d --- /dev/null +++ b/src/SablierV2LockupTranched.sol @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; + +import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; +import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; +import { ISablierV2LockupTranched } from "./interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; +import { Helpers } from "./libraries/Helpers.sol"; +import { Lockup, LockupTranched } from "./types/DataTypes.sol"; + +/* + +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ + +██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ████████╗██████╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗███████╗██████╗ +██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ ╚══██╔══╝██╔══██╗██╔══██╗████╗ ██║██╔════╝██║ ██║██╔════╝██╔══██╗ +██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ ██║ ██████╔╝███████║██╔██╗ ██║██║ ███████║█████╗ ██║ ██║ +██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ ██║ ██╔══██╗██╔══██║██║╚██╗██║██║ ██╔══██║██╔══╝ ██║ ██║ +███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ ██║ ██║ ██║██║ ██║██║ ╚████║╚██████╗██║ ██║███████╗██████╔╝ +╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═════╝ + +*/ + +/// @title SablierV2LockupTranched +/// @notice See the documentation in {ISablierV2LockupTranched}. +contract SablierV2LockupTranched is + ISablierV2LockupTranched, // 6 inherited components + SablierV2Lockup // 14 inherited components +{ + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2LockupTranched + uint256 public immutable override MAX_TRANCHE_COUNT; + + /// @dev Stream tranches mapped by stream ids. + mapping(uint256 id => LockupTranched.Tranche[] tranches) internal _tranches; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Emits a {TransferAdmin} event. + /// @param initialAdmin The address of the initial contract admin. + /// @param initialComptroller The address of the initial comptroller. + /// @param initialNFTDescriptor The address of the NFT descriptor contract. + /// @param maxTrancheCount The maximum number of tranches allowed in a stream. + constructor( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + ISablierV2NFTDescriptor initialNFTDescriptor, + uint256 maxTrancheCount + ) + ERC721("Sablier V2 Lockup Tranched NFT", "SAB-V2-LOCKUP-TRA") + SablierV2Lockup(initialAdmin, initialComptroller, initialNFTDescriptor) + { + MAX_TRANCHE_COUNT = maxTrancheCount; + nextStreamId = 1; + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2LockupTranched + function getRange(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupTranched.Range memory range) + { + range = LockupTranched.Range({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); + } + + /// @inheritdoc ISablierV2LockupTranched + function getStream(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupTranched.StreamLT memory stream) + { + // Retrieve the lockup stream from storage. + Lockup.Stream memory lockupStream = _streams[streamId]; + + // Settled streams cannot be canceled. + if (_statusOf(streamId) == Lockup.Status.SETTLED) { + lockupStream.isCancelable = false; + } + + stream = LockupTranched.StreamLT({ + amounts: lockupStream.amounts, + asset: lockupStream.asset, + endTime: lockupStream.endTime, + isCancelable: lockupStream.isCancelable, + isTransferable: lockupStream.isTransferable, + isDepleted: lockupStream.isDepleted, + isStream: lockupStream.isStream, + sender: lockupStream.sender, + startTime: lockupStream.startTime, + tranches: _tranches[streamId], + wasCanceled: lockupStream.wasCanceled + }); + } + + /// @inheritdoc ISablierV2LockupTranched + function getTranches(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupTranched.Tranche[] memory tranches) + { + tranches = _tranches[streamId]; + } + + /// @inheritdoc ISablierV2LockupTranched + function streamedAmountOf(uint256 streamId) + public + view + override(SablierV2Lockup, ISablierV2LockupTranched) + returns (uint128) + { + return super.streamedAmountOf(streamId); + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2LockupTranched + function createWithDurations(LockupTranched.CreateWithDurations calldata params) + external + override + noDelegateCall + returns (uint256 streamId) + { + // Checks: check the durations and generate the canonical tranches. + LockupTranched.Tranche[] memory tranches = Helpers.checkDurationsAndCalculateTimestamps(params.tranches); + + // Checks, Effects and Interactions: create the stream. + streamId = _createWithTimestamps( + LockupTranched.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + asset: params.asset, + cancelable: params.cancelable, + transferable: params.transferable, + startTime: uint40(block.timestamp), + tranches: tranches, + broker: params.broker + }) + ); + } + + /// @inheritdoc ISablierV2LockupTranched + function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) + external + override + noDelegateCall + returns (uint256 streamId) + { + // Checks, Effects and Interactions: create the stream. + streamId = _createWithTimestamps(params); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc SablierV2Lockup + function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { + uint40 currentTime = uint40(block.timestamp); + + LockupTranched.Tranche[] memory tranches = _tranches[streamId]; + + // If the first timestamp in the tranches is in the future, return zero. + if (tranches[0].timestamp > currentTime) { + return 0; + } + + // If the end time is not in the future, return the deposited amount. + if (_streams[streamId].endTime <= currentTime) { + return _streams[streamId].amounts.deposited; + } + + // Sum the amounts in all tranches that precede the current time. + uint128 streamedAmount = tranches[0].amount; + uint40 currentTrancheTimestamp = tranches[1].timestamp; + uint256 index = 1; + + // Using unchecked arithmetic is safe here because the sums of the tranche amounts are equal to the total amount + // at this point. + unchecked { + while (currentTrancheTimestamp <= currentTime) { + streamedAmount += tranches[index].amount; + index += 1; + currentTrancheTimestamp = tranches[index].timestamp; + } + } + + return streamedAmount; + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev See the documentation for the user-facing functions that call this internal function. + function _createWithTimestamps(LockupTranched.CreateWithTimestamps memory params) + internal + returns (uint256 streamId) + { + // Safe Interactions: query the protocol fee. This is safe because it's a known Sablier contract that does + // not call other unknown contracts. + UD60x18 protocolFee = comptroller.protocolFees(params.asset); + + // Checks: check the fees and calculate the fee amounts. + Lockup.CreateAmounts memory createAmounts = + Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); + + // Checks: validate the user-provided parameters. + Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.tranches, MAX_TRANCHE_COUNT, params.startTime); + + // Load the stream id in a variable. + streamId = nextStreamId; + + // Effects: create the stream. + Lockup.Stream storage stream = _streams[streamId]; + stream.amounts.deposited = createAmounts.deposit; + stream.asset = params.asset; + stream.isCancelable = params.cancelable; + stream.isTransferable = params.transferable; + stream.isStream = true; + stream.sender = params.sender; + stream.startTime = params.startTime; + + unchecked { + // The tranche count cannot be zero at this point. + uint256 trancheCount = params.tranches.length; + stream.endTime = params.tranches[trancheCount - 1].timestamp; + + // Effects: store the tranches. Since Solidity lacks a syntax for copying arrays directly from + // memory to storage, a manual approach is necessary. See https://github.com/ethereum/solidity/issues/12783. + for (uint256 i = 0; i < trancheCount; ++i) { + _tranches[streamId].push(params.tranches[i]); + } + + // Effects: bump the next stream id and record the protocol fee. + // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. + nextStreamId = streamId + 1; + protocolRevenues[params.asset] = protocolRevenues[params.asset] + createAmounts.protocolFee; + } + + // Effects: mint the NFT to the recipient. + _mint({ to: params.recipient, tokenId: streamId }); + + // Interactions: transfer the deposit and the protocol fee. + // Using unchecked arithmetic because the deposit and the protocol fee are bounded by the total amount. + unchecked { + params.asset.safeTransferFrom({ + from: msg.sender, + to: address(this), + value: createAmounts.deposit + createAmounts.protocolFee + }); + } + + // Interactions: pay the broker fee, if not zero. + if (createAmounts.brokerFee > 0) { + params.asset.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee }); + } + + // Log the newly created stream. + emit ISablierV2LockupTranched.CreateLockupTranchedStream({ + streamId: streamId, + funder: msg.sender, + sender: params.sender, + recipient: params.recipient, + amounts: createAmounts, + asset: params.asset, + cancelable: params.cancelable, + transferable: params.transferable, + tranches: params.tranches, + range: LockupTranched.Range({ start: stream.startTime, end: stream.endTime }), + broker: params.broker.account + }); + } +} diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 0d3486ed2..db7fd5656 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -300,6 +300,8 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { return "Lockup Linear"; } else if (symbol.equal("SAB-V2-LOCKUP-DYN")) { return "Lockup Dynamic"; + } else if (symbol.equal("SAB-V2-LOCKUP-TRA")) { + return "Lockup Tranched"; } else { revert Errors.SablierV2NFTDescriptor_UnknownNFT(sablier, symbol); } diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index ef6e68ea9..2bf973b8d 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -44,12 +44,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice The maximum number of segments allowed in a stream. - /// @dev This is initialized at construction time and cannot be changed later. - function MAX_SEGMENT_COUNT() external view returns (uint256); - - /// @notice Retrieves the stream's range, which is a struct containing (i) the stream's start time and (ii) end - /// time, both as Unix timestamps. + /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream id for the query. function getRange(uint256 streamId) external view returns (LockupDynamic.Range memory range); @@ -64,6 +59,10 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @param streamId The stream id for the query. function getStream(uint256 streamId) external view returns (LockupDynamic.StreamLD memory stream); + /// @notice The maximum number of segments allowed in a stream. + /// @dev This is initialized at construction time and cannot be changed later. + function MAX_SEGMENT_COUNT() external view returns (uint256); + /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. /// /// When the stream is warm, the streaming function is: diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index f2a5fdd7c..5ffc6f5e9 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -49,8 +49,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param streamId The stream id for the query. function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); - /// @notice Retrieves the stream's range, which is a struct containing (i) the stream's start time, (ii) cliff - /// time, and (iii) end time, all as Unix timestamps. + /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream id for the query. function getRange(uint256 streamId) external view returns (LockupLinear.Range memory range); diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol new file mode 100644 index 000000000..14f47aac8 --- /dev/null +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { Lockup, LockupTranched } from "../types/DataTypes.sol"; +import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; + +/// @title ISablierV2LockupTranched +/// @notice Creates and manages Lockup streams with tranches. +interface ISablierV2LockupTranched is ISablierV2Lockup { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a stream is created. + /// @param streamId The id of the newly created stream. + /// @param funder The address which has funded the stream. + /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream. + /// @param recipient The address toward which to stream the assets. + /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the + /// 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 tranches The tranches 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. + event CreateLockupTranchedStream( + uint256 streamId, + address funder, + address indexed sender, + address indexed recipient, + Lockup.CreateAmounts amounts, + IERC20 indexed asset, + bool cancelable, + bool transferable, + LockupTranched.Tranche[] tranches, + LockupTranched.Range range, + address broker + ); + + /*////////////////////////////////////////////////////////////////////////// + CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream id for the query. + function getRange(uint256 streamId) external view returns (LockupTranched.Range memory range); + + /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream id for the query. + function getStream(uint256 streamId) external view returns (LockupTranched.StreamLT memory stream); + + /// @notice Retrieves the tranches the protocol uses to compose the custom distribution curve. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream id for the query. + function getTranches(uint256 streamId) external view returns (LockupTranched.Tranche[] memory tranches); + + /// @notice The maximum number of tranches allowed in a stream. + /// @dev This is initialized at construction time and cannot be changed later. + function MAX_TRANCHE_COUNT() external view returns (uint256); + + /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. + /// + /// When the stream is warm, the streaming function is: + /// + /// $$ + /// f(x) = \Sigma(esa) + /// $$ + /// + /// Where: + /// + /// - $\Sigma(esa)$ is the sum of all elapsed tranches' amounts. + /// + /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited + /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent + /// to the total amount withdrawn. + /// + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream id for the query. + function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a stream by setting the start time to `block.timestamp`, and the end time to the sum of + /// `block.timestamp` and all specified time durations. The tranche timestamps are derived from these + /// durations. The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. + /// + /// @dev Emits a {Transfer} and {CreateLockupTrancheStream} event. + /// + /// Requirements: + /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. + /// + /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. + /// @return streamId The id of the newly created stream. + function createWithDurations(LockupTranched.CreateWithDurations calldata params) + external + returns (uint256 streamId); + + /// @notice Creates a stream with the provided tranche timestamps, implying the end time from the last timestamp. + /// The stream is funded by `msg.sender` and is wrapped in an ERC-721 NFT. + /// + /// @dev Emits a {Transfer} and {CreateLockupTrancheStream} event. + /// + /// Notes: + /// - As long as the tranche timestamps are arranged in ascending order, it is not an error for some + /// of them to be in the past. + /// + /// Requirements: + /// - Must not be delegate called. + /// - `params.totalAmount` must be greater than zero. + /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. + /// - `params.tranches` must have at least one tranche, but not more than `MAX_SEGMENT_COUNT`. + /// - `params.startTime` must be less than the first tranche's timestamp. + /// - The tranche timestamps must be arranged in ascending order. + /// - The last tranche timestamp (i.e. the stream's end time) must be in the future. + /// - The sum of the tranche amounts must equal the deposit amount. + /// - `params.recipient` must not be the zero address. + /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. + /// + /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. + /// @return streamId The id of the newly created stream. + function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) + external + returns (uint256 streamId); +} diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index dd7c6ad57..fad6a551f 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -97,7 +97,7 @@ library Errors { /// @notice Thrown when trying to create a stream with no segments. error SablierV2LockupDynamic_SegmentCountZero(); - /// @notice Thrown when trying to create a stream with unordered segment timestampts. + /// @notice Thrown when trying to create a stream with unordered segment timestamps. error SablierV2LockupDynamic_SegmentTimestampsNotOrdered( uint256 index, uint40 previousTimestamp, uint40 currentTimestamp ); @@ -130,4 +130,31 @@ library Errors { /// @notice Thrown when trying to generate the token URI for an unknown ERC-721 NFT contract. error SablierV2NFTDescriptor_UnknownNFT(IERC721Metadata nft, string symbol); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHE + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when trying to create a stream with a deposit amount not equal to the sum of the + /// tranche amounts. + error SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum( + uint128 depositAmount, uint128 trancheAmountsSum + ); + + /// @notice Thrown when trying to create a stream with a start time not strictly less than the first + /// tranche timestamp. + error SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( + uint40 startTime, uint40 firstTrancheTimestamp + ); + + /// @notice Thrown when trying to create a stream with more tranches than the maximum allowed. + error SablierV2LockupTranched_TrancheCountTooHigh(uint256 count); + + /// @notice Thrown when trying to create a stream with no tranches. + error SablierV2LockupTranched_TrancheCountZero(); + + /// @notice Thrown when trying to create a stream with unordered tranche timestamps. + error SablierV2LockupTranched_TrancheTimestampsNotOrdered( + uint256 index, uint40 previousTimestamp, uint40 currentTimestamp + ); } diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 894ccf27a..88c372498 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Lockup, LockupDynamic, LockupLinear } from "../types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../types/DataTypes.sol"; import { Errors } from "./Errors.sol"; /// @title Helpers @@ -119,6 +119,36 @@ library Helpers { } } + /// @dev Checks the parameters of the {SablierV2LockupTranched-_createWithTimestamps} function. + function checkCreateWithTimestamps( + uint128 depositAmount, + LockupTranched.Tranche[] memory tranches, + uint256 maxTrancheCount, + uint40 startTime + ) + internal + view + { + // Checks: the deposit amount is not zero. + if (depositAmount == 0) { + revert Errors.SablierV2Lockup_DepositAmountZero(); + } + + // Checks: the tranche count is not zero. + uint256 trancheCount = tranches.length; + if (trancheCount == 0) { + revert Errors.SablierV2LockupTranched_TrancheCountZero(); + } + + // Checks: the tranche count is not greater than the maximum allowed. + if (trancheCount > maxTrancheCount) { + revert Errors.SablierV2LockupTranched_TrancheCountTooHigh(trancheCount); + } + + // Checks: requirements of tranches variables. + _checkTranches(tranches, depositAmount, startTime); + } + /// @dev Checks that the segment array counts match, and then adjusts the segments by calculating the timestamps. function checkDurationsAndCalculateTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) internal @@ -152,6 +182,35 @@ library Helpers { } } + /// @dev Checks that the tranche array counts match, and then adjusts the tranches by calculating the timestamps. + function checkDurationsAndCalculateTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + internal + view + returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) + { + uint256 trancheCount = tranches.length; + tranchesWithTimestamps = new LockupTranched.Tranche[](trancheCount); + + // Make the current time the stream's start time. + uint40 startTime = uint40(block.timestamp); + + // It is safe to use unchecked arithmetic because {_createWithTimestamps} will nonetheless check the soundness + // of the calculated tranche timestamps. + unchecked { + // Precompute the first tranche because of the need to add the start time to the first tranche duration. + tranchesWithTimestamps[0] = + LockupTranched.Tranche({ amount: tranches[0].amount, timestamp: startTime + tranches[0].duration }); + + // Copy the tranche amounts and calculate the tranche timestamps. + for (uint256 i = 1; i < trancheCount; ++i) { + tranchesWithTimestamps[i] = LockupTranched.Tranche({ + amount: tranches[i].amount, + timestamp: tranchesWithTimestamps[i - 1].timestamp + tranches[i].duration + }); + } + } + } + /*////////////////////////////////////////////////////////////////////////// PRIVATE CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -217,4 +276,66 @@ library Helpers { ); } } + + /// @dev Checks that: + /// + /// 1. The first timestamp is strictly greater than the start time. + /// 2. The timestamps are ordered chronologically. + /// 3. There are no duplicate timestamps. + /// 4. The deposit amount is equal to the sum of all tranche amounts. + function _checkTranches( + LockupTranched.Tranche[] memory tranches, + uint128 depositAmount, + uint40 startTime + ) + private + view + { + // Checks: the start time is strictly less than the first tranche timestamp. + if (startTime >= tranches[0].timestamp) { + revert Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( + startTime, tranches[0].timestamp + ); + } + + // Pre-declare the variables needed in the for loop. + uint128 trancheAmountsSum; + uint40 currentTimestamp; + uint40 previousTimestamp; + + // Iterate over the tranches to: + // + // 1. Calculate the sum of all tranche amounts. + // 2. Check that the timestamps are ordered. + uint256 count = tranches.length; + for (uint256 index = 0; index < count; ++index) { + // Add the current tranche amount to the sum. + trancheAmountsSum += tranches[index].amount; + + // Checks: the current timestamp is strictly greater than the previous timestamp. + currentTimestamp = tranches[index].timestamp; + if (currentTimestamp <= previousTimestamp) { + revert Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered( + index, previousTimestamp, currentTimestamp + ); + } + + // Make the current timestamp the previous timestamp of the next loop iteration. + previousTimestamp = currentTimestamp; + } + + // Checks: the last timestamp is in the future. + // When the loop exits, the current timestamp is the last timestamp, i.e. the stream's end time. + uint40 currentTime = uint40(block.timestamp); + if (currentTime >= currentTimestamp) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, currentTimestamp); + } + + // Checks: the deposit amount is equal to the tranche amounts sum. + if (depositAmount != trancheAmountsSum) { + revert Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum( + depositAmount, trancheAmountsSum + ); + } + } } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index f024ae71c..6743515ad 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -12,6 +12,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; // - Lockup // - LockupDynamic // - LockupLinear +// - LockupTranched // // You will notice that some structs contain "slot" annotations - they are used to indicate the // storage layout of the struct. It is more gas efficient to group small data types together so @@ -280,3 +281,98 @@ library LockupLinear { uint40 cliffTime; } } + +/// @notice Namespace for the structs used in {SablierV2LockupTranched}. +library LockupTranched { + /// @notice Struct encapsulating the parameters for the {SablierV2LockupTranched.createWithDurations} function. + /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the + /// same as `msg.sender`. + /// @param recipient The address receiving the assets. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential + /// fees, all denoted in units of the asset's decimals. + /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param cancelable Indicates if the stream is cancelable. + /// @param transferable Indicates if the stream NFT is transferable. + /// @param tranches Tranches with durations used to compose the custom streaming curve. Timestamps are calculated by + /// starting from `block.timestamp` and adding each duration to the previous timestamp. + /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. + struct CreateWithDurations { + address sender; + address recipient; + uint128 totalAmount; + IERC20 asset; + bool cancelable; + bool transferable; + TrancheWithDuration[] tranches; + Broker broker; + } + + /// @notice Struct encapsulating the parameters for the {SablierV2LockupTranched.createWithTimestamps} + /// function. + /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the + /// same as `msg.sender`. + /// @param recipient The address receiving the assets. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential + /// fees, all denoted in units of the asset's decimals. + /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param cancelable Indicates if the stream is cancelable. + /// @param transferable Indicates if the stream NFT is transferable. + /// @param startTime The Unix timestamp indicating the stream's start. + /// @param tranches Tranches used to compose the custom streaming curve. + /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. + struct CreateWithTimestamps { + address sender; + address recipient; + uint128 totalAmount; + IERC20 asset; + bool cancelable; + bool transferable; + uint40 startTime; + Tranche[] tranches; + Broker broker; + } + + /// @notice Struct encapsulating the time range. + /// @param start The Unix timestamp indicating the stream's start. + /// @param end The Unix timestamp indicating the stream's end. + struct Range { + uint40 start; + uint40 end; + } + + /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within + /// one call to the contract. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the tranches. + struct StreamLT { + address sender; + uint40 startTime; + uint40 endTime; + bool isCancelable; + bool wasCanceled; + IERC20 asset; + bool isDepleted; + bool isStream; + bool isTransferable; + Lockup.Amounts amounts; + Tranche[] tranches; + } + + /// @notice Tranche struct used in the Lockup Tranched stream. + /// @param amount The amount of assets to be unlocked in this tranche, denoted in units of the asset's decimals. + /// @param timestamp The Unix timestamp indicating this tranche's end. + struct Tranche { + // slot 0 + uint128 amount; + uint40 timestamp; + } + + /// @notice Tranche struct used at runtime in {SablierV2LockupTranched.createWithDurations}. + /// @param amount The amount of assets to be unlocked in this tranche, denoted in units of the asset's decimals. + /// @param duration The time difference in seconds between this tranche and the previous one. + struct TrancheWithDuration { + uint128 amount; + uint40 duration; + } +} diff --git a/test/Base.t.sol b/test/Base.t.sol index 5ebd294c2..0874e8b17 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -6,10 +6,12 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; @@ -45,6 +47,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi GoodSender internal goodSender; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; + ISablierV2LockupTranched internal lockupTranched; ISablierV2NFTDescriptor internal nftDescriptor; Noop internal noop; ERC20MissingReturn internal usdt; @@ -65,24 +68,28 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.label({ account: address(dai), newLabel: "DAI" }); vm.label({ account: address(goodRecipient), newLabel: "Good Recipient" }); vm.label({ account: address(goodSender), newLabel: "Good Sender" }); - vm.label({ account: address(nftDescriptor), newLabel: "NFT Descriptor" }); vm.label({ account: address(noop), newLabel: "Noop" }); vm.label({ account: address(usdt), newLabel: "USDT" }); - // Create users for testing. - users = Users({ - admin: createUser("Admin"), - alice: createUser("Alice"), - broker: createUser("Broker"), - eve: createUser("Eve"), - operator: createUser("Operator"), - recipient: createUser("Recipient"), - sender: createUser("Sender") - }); - // Deploy the defaults contract. defaults = new Defaults(); defaults.setAsset(dai); + + // Create the protocol admin. + users.admin = payable(makeAddr({ name: "Admin" })); + vm.startPrank({ msgSender: users.admin }); + + // Deploy the V2 Core contracts. + deployCoreConditionally(); + + // Create users for testing. + users.alice = createUser("Alice"); + users.broker = createUser("Broker"); + users.eve = createUser("Eve"); + users.operator = createUser("Operator"); + users.recipient = createUser("Recipient"); + users.sender = createUser("Sender"); + defaults.setUsers(users); // Warp to May 1, 2023 at 00:00 GMT to provide a more realistic testing environment. @@ -93,42 +100,24 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi HELPERS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Approves all V2 Core contracts to spend assets from the Sender, Recipient, Alice and Eve. - function approveProtocol() internal { - changePrank({ msgSender: users.sender }); - dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - - changePrank({ msgSender: users.recipient }); + /// @dev Approves all V2 Core contracts to spend assets from the address passed. + function approveProtocol(address from) internal { + changePrank({ msgSender: from }); dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); + dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - - changePrank({ msgSender: users.alice }); - dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - - changePrank({ msgSender: users.eve }); - dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - - // Finally, change the active prank back to the Admin. - changePrank({ msgSender: users.admin }); + usdt.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); } - /// @dev Generates a user, labels its address, and funds it with test assets. + /// @dev Generates a user, labels its address, funds it with test assets and approve the protocol contracts. function createUser(string memory name) internal returns (address payable) { address payable user = payable(makeAddr(name)); vm.deal({ account: user, newBalance: 100 ether }); deal({ token: address(dai), to: user, give: 1_000_000e18 }); deal({ token: address(usdt), to: user, give: 1_000_000e18 }); + approveProtocol({ from: user }); return user; } @@ -141,17 +130,18 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi if (!isTestOptimizedProfile()) { comptroller = new SablierV2Comptroller(users.admin); nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = - new SablierV2LockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); + lockupDynamic = new SablierV2LockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT()); lockupLinear = new SablierV2LockupLinear(users.admin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT()); } else { - (comptroller, lockupDynamic, lockupLinear, nftDescriptor) = - deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT()); + (comptroller, lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = + deployOptimizedCore(users.admin, defaults.MAX_COUNT(), defaults.MAX_COUNT()); } vm.label({ account: address(comptroller), newLabel: "Comptroller" }); vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); + vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); vm.label({ account: address(nftDescriptor), newLabel: "NFTDescriptor" }); } diff --git a/test/fork/Fork.t.sol b/test/fork/Fork.t.sol index 831f93095..755f2585d 100644 --- a/test/fork/Fork.t.sol +++ b/test/fork/Fork.t.sol @@ -36,14 +36,11 @@ abstract contract Fork_Test is Base_Test { // The base is set up after the fork is selected so that the base test contracts are deployed on the fork. Base_Test.setUp(); - // Deploy V2 Core. - deployCoreConditionally(); - // Label the contracts. labelContracts(); // Make the ASSET HOLDER the caller in this test suite. - vm.startPrank({ msgSender: HOLDER }); + changePrank({ msgSender: HOLDER }); // Query the initial balance of the ASSET HOLDER. initialHolderBalance = ASSET.balanceOf(HOLDER); diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index b9a983c4a..c5138e1d6 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -37,7 +37,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { address sender; address recipient; uint128 withdrawAmount; - bool transferable; UD60x18 protocolFee; uint40 startTime; uint40 warpTimestamp; @@ -120,7 +119,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); - params.transferable = true; // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); @@ -170,7 +168,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { amounts: vars.createAmounts, asset: ASSET, cancelable: true, - transferable: params.transferable, + transferable: true, segments: params.segments, range: vars.range, broker: params.broker.account @@ -184,7 +182,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { totalAmount: vars.totalAmount, asset: ASSET, cancelable: true, - transferable: params.transferable, + transferable: true, startTime: params.startTime, segments: params.segments, broker: params.broker diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index 65247b60a..c76b964d3 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -38,7 +38,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { address recipient; uint128 totalAmount; uint128 withdrawAmount; - bool transferable; UD60x18 protocolFee; uint40 warpTimestamp; LockupLinear.Range range; @@ -123,7 +122,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { params.range.start = boundUint40(params.range.start, currentTime - 1000 seconds, currentTime + 10_000 seconds); params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); - params.transferable = true; // Bound the end time so that it is always greater than both the current time and the cliff time (this is // a requirement of the protocol). @@ -173,7 +171,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { amounts: vars.createAmounts, asset: ASSET, cancelable: true, - transferable: params.transferable, + transferable: true, range: params.range, broker: params.broker.account }); @@ -186,7 +184,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { totalAmount: params.totalAmount, asset: ASSET, cancelable: true, - transferable: params.transferable, + transferable: true, range: params.range, broker: params.broker }) diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol new file mode 100644 index 000000000..6331e1b31 --- /dev/null +++ b/test/fork/LockupTranched.t.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; +import { Solarray } from "solarray/src/Solarray.sol"; + +import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { Fork_Test } from "./Fork.t.sol"; + +abstract contract LockupTranched_Fork_Test is Fork_Test { + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor(IERC20 asset, address holder) Fork_Test(asset, holder) { } + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + Fork_Test.setUp(); + + // Approve {SablierV2LockupTranched} to transfer the holder's assets. + // We use a low-level call to ignore reverts because the asset can have the missing return value bug. + (bool success,) = address(ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupTranched), MAX_UINT256))); + success; + } + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + struct Params { + address sender; + address recipient; + uint128 withdrawAmount; + UD60x18 protocolFee; + uint40 startTime; + uint40 warpTimestamp; + LockupTranched.Tranche[] tranches; + Broker broker; + } + + struct Vars { + // Generic vars + address actualNFTOwner; + uint256 actualLockupTranchedBalance; + uint256 actualRecipientBalance; + Lockup.Status actualStatus; + uint256[] balances; + address expectedNFTOwner; + uint256 expectedLockupTranchedBalance; + uint256 expectedRecipientBalance; + Lockup.Status expectedStatus; + uint256 initialLockupTranchedBalance; + uint256 initialRecipientBalance; + bool isCancelable; + bool isDepleted; + bool isSettled; + LockupTranched.Range range; + uint256 streamId; + // Create vars + uint256 actualBrokerBalance; + uint256 actualHolderBalance; + uint256 actualNextStreamId; + uint256 actualProtocolRevenues; + Lockup.CreateAmounts createAmounts; + uint256 expectedBrokerBalance; + uint256 expectedHolderBalance; + uint256 expectedProtocolRevenues; + uint256 expectedNextStreamId; + uint256 initialBrokerBalance; + uint256 initialProtocolRevenues; + uint128 totalAmount; + // Withdraw vars + uint128 actualWithdrawnAmount; + uint128 expectedWithdrawnAmount; + uint128 withdrawableAmount; + // Cancel vars + uint256 actualSenderBalance; + uint256 expectedSenderBalance; + uint256 initialSenderBalance; + uint128 recipientAmount; + uint128 senderAmount; + } + + /// @dev Checklist: + /// + /// - It should perform all expected ERC-20 transfers. + /// - It should create the stream. + /// - It should bump the next stream id. + /// - It should record the protocol fee. + /// - It should mint the NFT. + /// - It should emit a {CreateLockupTranchedStream} event. + /// - It may make a withdrawal. + /// - It may update the withdrawn amounts. + /// - It may emit a {WithdrawFromLockupStream} event. + /// - It may cancel the stream + /// - It may emit a {CancelLockupStream} event + /// + /// Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - Multiple values for the funder, recipient, sender, and broker + /// - Multiple values for the total amount + /// - Start time in the past + /// - Start time in the present + /// - Start time in the future + /// - Start time equal and not equal to the first tranche timestamp + /// - Multiple values for the broker fee, including zero + /// - Multiple values for the protocol fee, including zero + /// - Multiple values for the withdraw amount, including zero + /// - The whole gamut of stream statuses + function testForkFuzz_LockupTranched_CreateWithdrawCancel(Params memory params) external { + checkUsers(params.sender, params.recipient, params.broker.account, address(lockupTranched)); + vm.assume(params.tranches.length != 0); + params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); + params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(params.tranches, params.startTime); + + // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + Vars memory vars; + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts({ + upperBound: uint128(initialHolderBalance), + tranches: params.tranches, + protocolFee: params.protocolFee, + brokerFee: params.broker.fee + }); + + // Set the fuzzed protocol fee. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: ASSET, newProtocolFee: params.protocolFee }); + + // Make the holder the caller. + changePrank(HOLDER); + + /*////////////////////////////////////////////////////////////////////////// + CREATE + //////////////////////////////////////////////////////////////////////////*/ + + // Load the pre-create protocol revenues. + vars.initialProtocolRevenues = lockupTranched.protocolRevenues(ASSET); + + // Load the pre-create asset balances. + vars.balances = + getTokenBalances(address(ASSET), Solarray.addresses(address(lockupTranched), params.broker.account)); + vars.initialLockupTranchedBalance = vars.balances[0]; + vars.initialBrokerBalance = vars.balances[1]; + + vars.streamId = lockupTranched.nextStreamId(); + vars.range = LockupTranched.Range({ + start: params.startTime, + end: params.tranches[params.tranches.length - 1].timestamp + }); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: vars.streamId }); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit CreateLockupTranchedStream({ + streamId: vars.streamId, + funder: HOLDER, + sender: params.sender, + recipient: params.recipient, + amounts: vars.createAmounts, + asset: ASSET, + cancelable: true, + transferable: true, + tranches: params.tranches, + range: vars.range, + broker: params.broker.account + }); + + // Create the stream. + lockupTranched.createWithTimestamps( + LockupTranched.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: vars.totalAmount, + asset: ASSET, + cancelable: true, + transferable: true, + startTime: params.startTime, + tranches: params.tranches, + broker: params.broker + }) + ); + + // Check if the stream is settled. It is possible for a lockupTranched stream to settle at the time of creation + // because some tranche amounts can be zero. + vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + vars.isCancelable = vars.isSettled ? false : true; + + // Assert that the stream has been created. + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(vars.streamId); + assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); + assertEq(actualStream.asset, ASSET, "asset"); + assertEq(actualStream.endTime, vars.range.end, "endTime"); + assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); + assertEq(actualStream.isDepleted, false, "isDepleted"); + assertEq(actualStream.isTransferable, true, "isTransferable"); + assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.tranches, params.tranches, "tranches"); + assertEq(actualStream.sender, params.sender, "sender"); + assertEq(actualStream.startTime, params.startTime, "startTime"); + assertEq(actualStream.wasCanceled, false, "wasCanceled"); + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(vars.streamId); + if (params.startTime > getBlockTimestamp()) { + vars.expectedStatus = Lockup.Status.PENDING; + } else if (vars.isSettled) { + vars.expectedStatus = Lockup.Status.SETTLED; + } else { + vars.expectedStatus = Lockup.Status.STREAMING; + } + assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); + + // Assert that the next stream id has been bumped. + vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.expectedNextStreamId = vars.streamId + 1; + assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); + + // Assert that the protocol fee has been recorded. + vars.actualProtocolRevenues = lockupTranched.protocolRevenues(ASSET); + vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; + assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "post-create protocolRevenues"); + + // Assert that the NFT has been minted. + vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: vars.streamId }); + vars.expectedNFTOwner = params.recipient; + assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner"); + + // Load the post-create asset balances. + vars.balances = + getTokenBalances(address(ASSET), Solarray.addresses(address(lockupTranched), HOLDER, params.broker.account)); + vars.actualLockupTranchedBalance = vars.balances[0]; + vars.actualHolderBalance = vars.balances[1]; + vars.actualBrokerBalance = vars.balances[2]; + + // Assert that the contract's balance has been updated. + vars.expectedLockupTranchedBalance = + vars.initialLockupTranchedBalance + vars.createAmounts.deposit + vars.createAmounts.protocolFee; + assertEq( + vars.actualLockupTranchedBalance, + vars.expectedLockupTranchedBalance, + "post-create lockupTranched contract balance" + ); + + // Assert that the holder's balance has been updated. + vars.expectedHolderBalance = initialHolderBalance - vars.totalAmount; + assertEq(vars.actualHolderBalance, vars.expectedHolderBalance, "post-create Holder balance"); + + // Assert that the broker's balance has been updated. + vars.expectedBrokerBalance = vars.initialBrokerBalance + vars.createAmounts.brokerFee; + assertEq(vars.actualBrokerBalance, vars.expectedBrokerBalance, "post-create Broker balance"); + + /*////////////////////////////////////////////////////////////////////////// + WITHDRAW + //////////////////////////////////////////////////////////////////////////*/ + + // Simulate the passage of time. + params.warpTimestamp = boundUint40(params.warpTimestamp, vars.range.start, vars.range.end + 100 seconds); + vm.warp({ timestamp: params.warpTimestamp }); + + // Bound the withdraw amount. + vars.withdrawableAmount = lockupTranched.withdrawableAmountOf(vars.streamId); + params.withdrawAmount = boundUint128(params.withdrawAmount, 0, vars.withdrawableAmount); + + // Check if the stream has settled or will get depleted. It is possible for the stream to be just settled + // and not depleted because the withdraw amount is fuzzed. + vars.isDepleted = params.withdrawAmount == vars.createAmounts.deposit; + vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + + // Only run the withdraw tests if the withdraw amount is not zero. + if (params.withdrawAmount > 0) { + // Load the pre-withdraw asset balances. + vars.initialLockupTranchedBalance = vars.actualLockupTranchedBalance; + vars.initialRecipientBalance = ASSET.balanceOf(params.recipient); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit WithdrawFromLockupStream({ + streamId: vars.streamId, + to: params.recipient, + asset: ASSET, + amount: params.withdrawAmount + }); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: vars.streamId }); + + // Make the withdrawal. + changePrank({ msgSender: params.recipient }); + lockupTranched.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(vars.streamId); + if (vars.isDepleted) { + vars.expectedStatus = Lockup.Status.DEPLETED; + } else if (vars.isSettled) { + vars.expectedStatus = Lockup.Status.SETTLED; + } else { + vars.expectedStatus = Lockup.Status.STREAMING; + } + assertEq(vars.actualStatus, vars.expectedStatus, "post-withdraw stream status"); + + // Assert that the withdrawn amount has been updated. + vars.actualWithdrawnAmount = lockupTranched.getWithdrawnAmount(vars.streamId); + vars.expectedWithdrawnAmount = params.withdrawAmount; + assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount"); + + // Load the post-withdraw asset balances. + vars.balances = + getTokenBalances(address(ASSET), Solarray.addresses(address(lockupTranched), params.recipient)); + vars.actualLockupTranchedBalance = vars.balances[0]; + vars.actualRecipientBalance = vars.balances[1]; + + // Assert that the contract's balance has been updated. + vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance - uint256(params.withdrawAmount); + assertEq( + vars.actualLockupTranchedBalance, + vars.expectedLockupTranchedBalance, + "post-withdraw lockupTranched contract balance" + ); + + // Assert that the Recipient's balance has been updated. + vars.expectedRecipientBalance = vars.initialRecipientBalance + uint256(params.withdrawAmount); + assertEq(vars.actualRecipientBalance, vars.expectedRecipientBalance, "post-withdraw Recipient balance"); + } + + /*////////////////////////////////////////////////////////////////////////// + CANCEL + //////////////////////////////////////////////////////////////////////////*/ + + // Only run the cancel tests if the stream is neither depleted nor settled. + if (!vars.isDepleted && !vars.isSettled) { + // Load the pre-cancel asset balances. + vars.balances = getTokenBalances( + address(ASSET), Solarray.addresses(address(lockupTranched), params.sender, params.recipient) + ); + vars.initialLockupTranchedBalance = vars.balances[0]; + vars.initialSenderBalance = vars.balances[1]; + vars.initialRecipientBalance = vars.balances[2]; + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + vars.senderAmount = lockupTranched.refundableAmountOf(vars.streamId); + vars.recipientAmount = lockupTranched.withdrawableAmountOf(vars.streamId); + emit CancelLockupStream( + vars.streamId, params.sender, params.recipient, ASSET, vars.senderAmount, vars.recipientAmount + ); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: vars.streamId }); + + // Cancel the stream. + changePrank({ msgSender: params.sender }); + lockupTranched.cancel(vars.streamId); + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(vars.streamId); + vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED; + assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status"); + + // Load the post-cancel asset balances. + vars.balances = getTokenBalances( + address(ASSET), Solarray.addresses(address(lockupTranched), params.sender, params.recipient) + ); + vars.actualLockupTranchedBalance = vars.balances[0]; + vars.actualSenderBalance = vars.balances[1]; + vars.actualRecipientBalance = vars.balances[2]; + + // Assert that the contract's balance has been updated. + vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance - uint256(vars.senderAmount); + assertEq( + vars.actualLockupTranchedBalance, + vars.expectedLockupTranchedBalance, + "post-cancel lockupTranched contract balance" + ); + + // Assert that the Sender's balance has been updated. + vars.expectedSenderBalance = vars.initialSenderBalance + uint256(vars.senderAmount); + assertEq(vars.actualSenderBalance, vars.expectedSenderBalance, "post-cancel Sender balance"); + + // Assert that the Recipient's balance has not changed. + vars.expectedRecipientBalance = vars.initialRecipientBalance; + assertEq(vars.actualRecipientBalance, vars.expectedRecipientBalance, "post-cancel Recipient balance"); + } + + // Assert that the NFT has not been burned. + vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: vars.streamId }); + vars.expectedNFTOwner = params.recipient; + assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-cancel NFT owner"); + } +} diff --git a/test/fork/assets/DAI.t.sol b/test/fork/assets/DAI.t.sol index 6089fbca6..6bf507732 100644 --- a/test/fork/assets/DAI.t.sol +++ b/test/fork/assets/DAI.t.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; +import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev A typical 18-decimal ERC-20 asset with a normal total supply. IERC20 constant ASSET = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -13,3 +14,5 @@ address constant HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14; contract DAI_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract DAI_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } + +contract DAI_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/EURS.t.sol b/test/fork/assets/EURS.t.sol index 3586f5514..d75a7ca01 100644 --- a/test/fork/assets/EURS.t.sol +++ b/test/fork/assets/EURS.t.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; +import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with 2 decimals. IERC20 constant ASSET = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8); @@ -13,3 +14,5 @@ address constant HOLDER = 0x9712c160925403A9458BfC6bBD7D8a1E694C984a; contract EURS_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract EURS_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } + +contract EURS_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/SHIB.t.sol b/test/fork/assets/SHIB.t.sol index d67aeef1a..6d2f9dcbd 100644 --- a/test/fork/assets/SHIB.t.sol +++ b/test/fork/assets/SHIB.t.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; +import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with a large total supply. IERC20 constant ASSET = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); @@ -13,3 +14,5 @@ address constant HOLDER = 0x73AF3bcf944a6559933396c1577B257e2054D935; contract SHIB_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract SHIB_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } + +contract SHIB_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDC.t.sol b/test/fork/assets/USDC.t.sol index c76a4c2cd..f253f779a 100644 --- a/test/fork/assets/USDC.t.sol +++ b/test/fork/assets/USDC.t.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; +import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant ASSET = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); @@ -13,3 +14,5 @@ address constant HOLDER = 0x09528d637deb5857dc059dddE6316D465a8b3b69; contract USDC_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract USDC_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } + +contract USDC_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDT.t.sol b/test/fork/assets/USDT.t.sol index c88181bf8..d2d803eec 100644 --- a/test/fork/assets/USDT.t.sol +++ b/test/fork/assets/USDT.t.sol @@ -5,6 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; +import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant ASSET = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); @@ -13,3 +14,5 @@ address constant HOLDER = 0xee5B5B923fFcE93A870B3104b7CA09c3db80047A; contract USDT_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract USDT_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } + +contract USDT_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index 8bfe557b2..085090ac5 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -27,17 +27,11 @@ abstract contract Integration_Test is Base_Test { function setUp() public virtual override { Base_Test.setUp(); - // Deploy V2 Core. - deployCoreConditionally(); - // Label the contracts. labelContracts(); // Make the Admin the default caller in this test suite. - vm.startPrank({ msgSender: users.admin }); - - // Approve V2 Core to spend assets from the users. - approveProtocol(); + changePrank({ msgSender: users.admin }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index 697505783..f4e92bdde 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -31,9 +31,8 @@ import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptrol import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; +import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -435,20 +434,6 @@ contract Withdraw_LockupDynamic_Integration_Concrete_Test is } } -contract WithdrawHooks_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Concrete_Test, - WithdrawHooks_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) - { - LockupDynamic_Integration_Concrete_Test.setUp(); - WithdrawHooks_Integration_Concrete_Test.setUp(); - } -} - contract WithdrawMax_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index 97d32973d..d5f018cca 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -16,7 +16,7 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In initialAdmin: users.admin, initialComptroller: comptroller, initialNFTDescriptor: nftDescriptor, - maxSegmentCount: defaults.MAX_SEGMENT_COUNT() + maxSegmentCount: defaults.MAX_COUNT() }); // {SablierV2Base.constructor} @@ -39,7 +39,7 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In // {SablierV2LockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); - uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); - assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_SEGMENT_COUNT"); + uint256 expectedMaxSegmentCount = defaults.MAX_COUNT(); + assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_COUNT"); } } diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 4ae6afc20..6c3ea8406 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -67,7 +67,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is { unchecked { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDuration[] memory segments = defaults.createWithDurationsLD().segments; + LockupDynamic.SegmentWithDuration[] memory segments = defaults.segmentsWithDurations(); segments[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 524a69d30..621963bab 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -66,7 +66,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenDepositAmountNotZero whenSegmentCountNotZero { - uint256 segmentCount = defaults.MAX_SEGMENT_COUNT() + 1; + uint256 segmentCount = defaults.MAX_COUNT() + 1; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index e6540ba09..02a7b9c5b 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -34,7 +34,6 @@ import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -436,20 +435,6 @@ contract Withdraw_LockupLinear_Integration_Concrete_Test is } } -contract WithdrawHooks_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Concrete_Test, - WithdrawHooks_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) - { - LockupLinear_Integration_Concrete_Test.setUp(); - WithdrawHooks_Integration_Concrete_Test.setUp(); - } -} - contract WithdrawMax_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol new file mode 100644 index 000000000..c56e06c35 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; + +import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; +import { Integration_Test } from "../../Integration.t.sol"; +import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; +import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; +import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; +import { ClaimProtocolRevenues_Integration_Concrete_Test } from + "../lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol"; +import { GetAsset_Integration_Concrete_Test } from "../lockup/get-asset/getAsset.t.sol"; +import { GetDepositedAmount_Integration_Concrete_Test } from "../lockup/get-deposited-amount/getDepositedAmount.t.sol"; +import { GetEndTime_Integration_Concrete_Test } from "../lockup/get-end-time/getEndTime.t.sol"; +import { GetRecipient_Integration_Concrete_Test } from "../lockup/get-recipient/getRecipient.t.sol"; +import { GetRefundedAmount_Integration_Concrete_Test } from "../lockup/get-refunded-amount/getRefundedAmount.t.sol"; +import { GetSender_Integration_Concrete_Test } from "../lockup/get-sender/getSender.t.sol"; +import { GetStartTime_Integration_Concrete_Test } from "../lockup/get-start-time/getStartTime.t.sol"; +import { GetWithdrawnAmount_Integration_Concrete_Test } from "../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; +import { IsCancelable_Integration_Concrete_Test } from "../lockup/is-cancelable/isCancelable.t.sol"; +import { IsCold_Integration_Concrete_Test } from "../lockup/is-cold/isCold.t.sol"; +import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDepleted.t.sol"; +import { IsStream_Integration_Concrete_Test } from "../lockup/is-stream/isStream.t.sol"; +import { IsTransferable_Integration_Concrete_Test } from "../lockup/is-transferable/isTransferable.t.sol"; +import { IsWarm_Integration_Concrete_Test } from "../lockup/is-warm/isWarm.t.sol"; +import { ProtocolRevenues_Integration_Concrete_Test } from "../lockup/protocol-revenues/protocolRevenues.t.sol"; +import { RefundableAmountOf_Integration_Concrete_Test } from "../lockup/refundable-amount-of/refundableAmountOf.t.sol"; +import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce.t.sol"; +import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptroller/setComptroller.t.sol"; +import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; +import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; +import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; +import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; +import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; +import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from + "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; +import { WithdrawMultiple_Integration_Concrete_Test } from "../lockup/withdraw-multiple/withdrawMultiple.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED ABSTRACT TEST +//////////////////////////////////////////////////////////////////////////*/ + +/// @notice Common testing logic needed across {SablierV2LockupTranched} integration concrete tests. +abstract contract LockupTranched_Integration_Concrete_Test is + Integration_Test, + LockupTranched_Integration_Shared_Test +{ + function setUp() public virtual override(Integration_Test, LockupTranched_Integration_Shared_Test) { + // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is + // allowed in Solidity, and {Base_Test-setUp} will only be called once. + Integration_Test.setUp(); + LockupTranched_Integration_Shared_Test.setUp(); + + // Cast the LockupTranched contract as {ISablierV2Base} and {ISablierV2Lockup}. + base = ISablierV2Lockup(lockupTranched); + lockup = ISablierV2Lockup(lockupTranched); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Burn_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + Burn_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, Burn_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + Burn_Integration_Concrete_Test.setUp(); + } +} + +contract Cancel_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + Cancel_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, Cancel_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + Cancel_Integration_Concrete_Test.setUp(); + } +} + +contract CancelMultiple_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + CancelMultiple_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, CancelMultiple_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + CancelMultiple_Integration_Concrete_Test.setUp(); + } +} + +contract ClaimProtocolRevenues_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + ClaimProtocolRevenues_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, ClaimProtocolRevenues_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + ClaimProtocolRevenues_Integration_Concrete_Test.setUp(); + } +} + +contract GetAsset_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetAsset_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetAsset_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetAsset_Integration_Concrete_Test.setUp(); + } +} + +contract GetDepositedAmount_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetDepositedAmount_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetDepositedAmount_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetDepositedAmount_Integration_Concrete_Test.setUp(); + } +} + +contract GetEndTime_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetEndTime_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetEndTime_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetEndTime_Integration_Concrete_Test.setUp(); + } +} + +contract GetRecipient_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetRecipient_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetRecipient_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetRecipient_Integration_Concrete_Test.setUp(); + } +} + +contract GetRefundedAmount_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetRefundedAmount_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetRefundedAmount_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetRefundedAmount_Integration_Concrete_Test.setUp(); + } +} + +contract GetSender_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetSender_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetSender_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetSender_Integration_Concrete_Test.setUp(); + } +} + +contract GetStartTime_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetStartTime_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetStartTime_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetStartTime_Integration_Concrete_Test.setUp(); + } +} + +contract GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + GetWithdrawnAmount_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, GetWithdrawnAmount_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + GetWithdrawnAmount_Integration_Concrete_Test.setUp(); + } +} + +contract IsCancelable_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsCancelable_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsCancelable_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsCancelable_Integration_Concrete_Test.setUp(); + } +} + +contract IsCold_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsCold_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsCold_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsCold_Integration_Concrete_Test.setUp(); + } +} + +contract IsDepleted_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsDepleted_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsDepleted_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsDepleted_Integration_Concrete_Test.setUp(); + } +} + +contract IsStream_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsStream_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsStream_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsStream_Integration_Concrete_Test.setUp(); + } +} + +contract IsTransferable_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsTransferable_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsTransferable_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsTransferable_Integration_Concrete_Test.setUp(); + } +} + +contract IsWarm_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsWarm_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsWarm_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsWarm_Integration_Concrete_Test.setUp(); + } +} + +contract ProtocolRevenues_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + ProtocolRevenues_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, ProtocolRevenues_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + ProtocolRevenues_Integration_Concrete_Test.setUp(); + } +} + +contract RefundableAmountOf_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + RefundableAmountOf_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, RefundableAmountOf_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + RefundableAmountOf_Integration_Concrete_Test.setUp(); + } +} + +contract Renounce_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + Renounce_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, Renounce_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + Renounce_Integration_Concrete_Test.setUp(); + } +} + +contract SetComptroller_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + SetComptroller_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, SetComptroller_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + SetComptroller_Integration_Concrete_Test.setUp(); + } +} + +contract SetNFTDescriptor_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + SetNFTDescriptor_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, SetNFTDescriptor_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + SetNFTDescriptor_Integration_Concrete_Test.setUp(); + } +} + +contract StatusOf_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + StatusOf_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, StatusOf_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + StatusOf_Integration_Concrete_Test.setUp(); + } +} + +contract TransferFrom_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + TransferFrom_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, TransferFrom_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + TransferFrom_Integration_Concrete_Test.setUp(); + } +} + +contract WasCanceled_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WasCanceled_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WasCanceled_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WasCanceled_Integration_Concrete_Test.setUp(); + } +} + +contract Withdraw_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + Withdraw_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, Withdraw_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + Withdraw_Integration_Concrete_Test.setUp(); + } +} + +contract WithdrawMax_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WithdrawMax_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WithdrawMax_Integration_Concrete_Test.setUp(); + } +} + +contract WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WithdrawMaxAndTransfer_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WithdrawMaxAndTransfer_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WithdrawMaxAndTransfer_Integration_Concrete_Test.setUp(); + } +} + +contract WithdrawMultiple_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WithdrawMultiple_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WithdrawMultiple_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WithdrawMultiple_Integration_Concrete_Test.setUp(); + } +} diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol new file mode 100644 index 000000000..6ff85982a --- /dev/null +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2LockupTranched } from "src/SablierV2LockupTranched.sol"; + +import { LockupTranched_Integration_Concrete_Test } from "./LockupTranched.t.sol"; + +contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { + function test_Constructor() external { + // Expect the relevant event to be emitted. + vm.expectEmit(); + emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); + + // Construct the contract. + SablierV2LockupTranched constructedLockupTranched = new SablierV2LockupTranched({ + initialAdmin: users.admin, + initialComptroller: comptroller, + initialNFTDescriptor: nftDescriptor, + maxTrancheCount: defaults.MAX_COUNT() + }); + + // {SablierV2Base.constructor} + address actualAdmin = constructedLockupTranched.admin(); + address expectedAdmin = users.admin; + assertEq(actualAdmin, expectedAdmin, "admin"); + + address actualComptroller = address(constructedLockupTranched.comptroller()); + address expectedComptroller = address(comptroller); + assertEq(actualComptroller, expectedComptroller, "comptroller"); + + // {SablierV2Lockup.constructor} + uint256 actualStreamId = constructedLockupTranched.nextStreamId(); + uint256 expectedStreamId = 1; + assertEq(actualStreamId, expectedStreamId, "nextStreamId"); + + address actualNFTDescriptor = address(constructedLockupTranched.nftDescriptor()); + address expectedNFTDescriptor = address(nftDescriptor); + assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); + + // {SablierV2lockupTranched.constructor} + uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); + uint256 expectedMaxTrancheCount = defaults.MAX_COUNT(); + assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_COUNT"); + } +} diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol new file mode 100644 index 000000000..39575b99a --- /dev/null +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "src/libraries/Errors.sol"; +import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup-tranched/createWithDurations.t.sol"; +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + CreateWithDurations_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, CreateWithDurations_Integration_Shared_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + CreateWithDurations_Integration_Shared_Test.setUp(); + streamId = lockupTranched.nextStreamId(); + } + + /// @dev it should revert. + function test_RevertWhen_DelegateCalled() external { + bytes memory callData = + abi.encodeCall(ISablierV2LockupTranched.createWithDurations, defaults.createWithDurationsLT()); + (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); + expectRevertDueToDelegateCall(success, returnData); + } + + /// @dev it should revert. + function test_RevertWhen_LoopCalculationOverflowsBlockGasLimit() external whenNotDelegateCalled { + LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](25_000); + vm.expectRevert(); + createDefaultStreamWithDurations(tranches); + } + + function test_RevertWhen_DurationsZero() + external + whenNotDelegateCalled + whenLoopCalculationsDoNotOverflowBlockGasLimit + { + uint40 startTime = getBlockTimestamp(); + LockupTranched.TrancheWithDuration[] memory tranches = defaults.createWithDurationsLT().tranches; + tranches[2].duration = 0; + uint256 index = 2; + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + index, + startTime + tranches[0].duration + tranches[1].duration, + startTime + tranches[0].duration + tranches[1].duration + ) + ); + createDefaultStreamWithDurations(tranches); + } + + function test_RevertWhen_TimestampsCalculationsOverflows_StartTimeNotLessThanFirstTrancheTimestamp() + external + whenNotDelegateCalled + whenLoopCalculationsDoNotOverflowBlockGasLimit + whenDurationsNotZero + { + unchecked { + uint40 startTime = getBlockTimestamp(); + LockupTranched.TrancheWithDuration[] memory tranches = defaults.tranchesWithDurations(); + tranches[0].duration = MAX_UINT40; + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + startTime, + startTime + tranches[0].duration + ) + ); + createDefaultStreamWithDurations(tranches); + } + } + + function test_RevertWhen_TimestampsCalculationsOverflows_TrancheTimestampsNotOrdered() + external + whenNotDelegateCalled + whenLoopCalculationsDoNotOverflowBlockGasLimit + whenDurationsNotZero + { + unchecked { + uint40 startTime = getBlockTimestamp(); + + // Create new tranches that overflow when the timestamps are eventually calculated. + LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](2); + tranches[0] = LockupTranched.TrancheWithDuration({ amount: 0, duration: startTime + 1 seconds }); + tranches[1] = defaults.tranchesWithDurations()[0]; + tranches[1].duration = MAX_UINT40; + + // Expect the relevant error to be thrown. + uint256 index = 1; + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + index, + startTime + tranches[0].duration, + startTime + tranches[0].duration + tranches[1].duration + ) + ); + + // Create the stream. + createDefaultStreamWithDurations(tranches); + } + } + + function test_CreateWithDurations() + external + whenNotDelegateCalled + whenLoopCalculationsDoNotOverflowBlockGasLimit + whenDurationsNotZero + whenTimestampsCalculationsDoNotOverflow + { + // Make the Sender the stream's funder + address funder = users.sender; + + // Load the initial protocol revenues. + uint128 initialProtocolRevenues = lockupTranched.protocolRevenues(dai); + + // Declare the range. + uint40 currentTime = getBlockTimestamp(); + LockupTranched.Range memory range = + LockupTranched.Range({ start: currentTime, end: currentTime + defaults.TOTAL_DURATION() }); + + LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].timestamp = range.start + tranchesWithDurations[0].duration; + tranches[1].timestamp = tranches[0].timestamp + tranchesWithDurations[1].duration; + tranches[2].timestamp = tranches[1].timestamp + tranchesWithDurations[2].duration; + + // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + expectCallToTransferFrom({ + from: funder, + to: address(lockupTranched), + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + }); + + // Expect the broker fee to be paid to the broker. + expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: streamId }); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit CreateLockupTranchedStream({ + streamId: streamId, + funder: funder, + sender: users.sender, + recipient: users.recipient, + amounts: defaults.lockupCreateAmounts(), + asset: dai, + cancelable: true, + transferable: true, + tranches: tranches, + range: range, + broker: users.broker + }); + + // Create the stream. + createDefaultStreamWithDurations(); + + // Assert that the stream has been created. + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); + LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); + expectedStream.endTime = range.end; + expectedStream.startTime = range.start; + expectedStream.tranches = tranches; + assertEq(actualStream, expectedStream); + + // Assert that the stream's status is "STREAMING". + Lockup.Status actualStatus = lockupTranched.statusOf(streamId); + Lockup.Status expectedStatus = Lockup.Status.STREAMING; + assertEq(actualStatus, expectedStatus); + + // Assert that the next stream id has been bumped. + uint256 actualNextStreamId = lockupTranched.nextStreamId(); + uint256 expectedNextStreamId = streamId + 1; + assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); + + // Assert that the protocol fee has been recorded. + uint128 actualProtocolRevenues = lockupTranched.protocolRevenues(dai); + uint128 expectedProtocolRevenues = initialProtocolRevenues + defaults.PROTOCOL_FEE_AMOUNT(); + assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); + + // Assert that the NFT has been minted. + address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + address expectedNFTOwner = users.recipient; + assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); + } +} diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree new file mode 100644 index 000000000..c1d36efc7 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree @@ -0,0 +1,23 @@ +createWithDurations.t.sol +├── when delegate called +│ └── it should revert +└── when not delegate called + ├── when the loop calculations overflow the block gas limit + │ └── it should revert + └── when the loop calculations do not overflow the block gas limit + ├── when at least one of the durations at index one or greater is zero + │ └── it should revert + └── when none of the durations is zero + ├── when the tranche timestamp calculations overflow uint256 + │ ├── when the start time is not less than the first tranche timestamp + │ │ └── it should revert + │ └── when the tranche timestamps are not ordered + │ └── it should revert + └── when the tranche timestamp calculations do not overflow uint256 + ├── it should create the stream + ├── it should bump the next stream id + ├── it should record the protocol fee + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupTranchedStream} event diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol new file mode 100644 index 000000000..27a8e07c3 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { stdError } from "forge-std/src/StdError.sol"; + +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "src/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { CreateWithTimestamps_Integration_Shared_Test } from + "../../../shared/lockup-tranched/createWithTimestamps.t.sol"; +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + CreateWithTimestamps_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, CreateWithTimestamps_Integration_Shared_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); + } + + function test_RevertWhen_DelegateCalled() external { + bytes memory callData = + abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, defaults.createWithTimestampsLT()); + (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); + expectRevertDueToDelegateCall(success, returnData); + } + + function test_RevertWhen_RecipientZeroAddress() external whenNotDelegateCalled { + address recipient = address(0); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); + createDefaultStreamWithRecipient(recipient); + } + + function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { + // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_FEE` + // is hard coded to 10%. + vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); + uint128 totalAmount = 0; + createDefaultStreamWithTotalAmount(totalAmount); + } + + function test_RevertWhen_TrancheCountZero() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + { + LockupTranched.Tranche[] memory tranches; + vm.expectRevert(Errors.SablierV2LockupTranched_TrancheCountZero.selector); + createDefaultStreamWithTranches(tranches); + } + + function test_RevertWhen_TrancheCountTooHigh() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + { + uint256 trancheCount = defaults.MAX_COUNT() + 1; + LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) + ); + createDefaultStreamWithTranches(tranches); + } + + function test_RevertWhen_TrancheAmountsSumOverflows() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + { + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].amount = MAX_UINT128; + tranches[1].amount = 1; + vm.expectRevert(stdError.arithmeticError); + createDefaultStreamWithTranches(tranches); + } + + function test_RevertWhen_StartTimeGreaterThanFirstTrancheTimestamp() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + { + // Change the timestamp of the first tranche. + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].timestamp = defaults.START_TIME() - 1 seconds; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + defaults.START_TIME(), + tranches[0].timestamp + ) + ); + + // Create the stream. + createDefaultStreamWithTranches(tranches); + } + + function test_RevertWhen_StartTimeEqualToFirstTrancheTimestamp() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + { + // Change the timestamp of the first tranche. + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].timestamp = defaults.START_TIME(); + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + defaults.START_TIME(), + tranches[0].timestamp + ) + ); + + // Create the stream. + createDefaultStreamWithTranches(tranches); + } + + function test_RevertWhen_TrancheTimestampsNotOrdered() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + { + // Swap the tranche timestamps. + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + (tranches[0].timestamp, tranches[1].timestamp) = (tranches[1].timestamp, tranches[0].timestamp); + + // Expect the relevant error to be thrown. + uint256 index = 1; + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + index, + tranches[0].timestamp, + tranches[1].timestamp + ) + ); + + // Create the stream. + createDefaultStreamWithTranches(tranches); + } + + function test_RevertGiven_EndTimeNotInTheFuture() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + { + uint40 endTime = defaults.END_TIME(); + vm.warp({ timestamp: endTime }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); + createDefaultStream(); + } + + function test_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + { + // Disable both the protocol and the broker fee so that they don't interfere with the calculations. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); + UD60x18 brokerFee = ZERO; + changePrank({ msgSender: users.sender }); + + // Adjust the default deposit amount. + uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); + uint128 depositAmount = defaultDepositAmount + 100; + + // Prepare the params. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: brokerFee }); + params.totalAmount = depositAmount; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + depositAmount, + defaultDepositAmount + ) + ); + + // Create the stream. + lockupTranched.createWithTimestamps(params); + } + + function test_RevertGiven_ProtocolFeeTooHigh() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + { + UD60x18 protocolFee = MAX_FEE + ud(1); + + // Set the protocol fee. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); + changePrank({ msgSender: users.sender }); + + // Run the test. + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) + ); + createDefaultStream(); + } + + function test_RevertWhen_BrokerFeeTooHigh() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + { + UD60x18 brokerFee = MAX_FEE + ud(1); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_FEE)); + createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); + } + + function test_RevertWhen_AssetNotContract() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + whenBrokerFeeNotTooHigh + { + address nonContract = address(8128); + + // Set the default protocol fee so that the test does not revert due to the deposit amount not being + // equal to the sum of the tranche amounts. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee(IERC20(nonContract), defaults.PROTOCOL_FEE()); + changePrank({ msgSender: users.sender }); + + // Run the test. + vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); + createDefaultStreamWithAsset(IERC20(nonContract)); + } + + function test_CreateWithTimestamps_AssetMissingReturnValue() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + whenBrokerFeeNotTooHigh + whenAssetContract + { + testCreateWithTimestamps(address(usdt)); + } + + function test_CreateWithTimestamps() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + whenBrokerFeeNotTooHigh + whenAssetContract + whenAssetERC20 + { + testCreateWithTimestamps(address(dai)); + } + + /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. + function testCreateWithTimestamps(address asset) internal { + // Make the Sender the stream's funder. + address funder = users.sender; + + // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: address(lockupTranched), + value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + }); + + // Expect the broker fee to be paid to the broker. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: users.broker, + value: defaults.BROKER_FEE_AMOUNT() + }); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: streamId }); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit CreateLockupTranchedStream({ + streamId: streamId, + funder: funder, + sender: users.sender, + recipient: users.recipient, + amounts: defaults.lockupCreateAmounts(), + tranches: defaults.tranches(), + asset: IERC20(asset), + cancelable: true, + transferable: true, + range: defaults.lockupTranchedRange(), + broker: users.broker + }); + + // Create the stream. + streamId = createDefaultStreamWithAsset(IERC20(asset)); + + // Assert that the stream has been created. + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); + LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); + expectedStream.asset = IERC20(asset); + assertEq(actualStream, expectedStream); + + // Assert that the stream's status is "PENDING". + Lockup.Status actualStatus = lockupTranched.statusOf(streamId); + Lockup.Status expectedStatus = Lockup.Status.PENDING; + assertEq(actualStatus, expectedStatus); + + // Assert that the next stream id has been bumped. + uint256 actualNextStreamId = lockupTranched.nextStreamId(); + uint256 expectedNextStreamId = streamId + 1; + assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); + + // Assert that the NFT has been minted. + address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + address expectedNFTOwner = users.recipient; + assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); + } +} diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree new file mode 100644 index 000000000..15667b77f --- /dev/null +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -0,0 +1,58 @@ +createWithTimestamps.t.sol +├── when delegate called +│ └── it should revert +└── when not delegate called + ├── when the recipient is the zero address + │ └── it should revert + └── when the recipient is not the zero address + ├── when the deposit amount is zero + │ └── it should revert + └── when the deposit amount is not zero + ├── when the tranche count is zero + │ └── it should revert + └── when the tranche count is not zero + ├── when the tranche count is too high + │ └── it should revert + └── when the tranche count is not too high + ├── when the tranche amounts sum overflows + │ └── it should revert + └── when the tranche amounts sum does not overflow + ├── when the start time is greater than the first tranche timestamp + │ └── it should revert + ├── when the start time is equal to the first tranche timestamp + │ └── it should revert + └── when the start time is less than the first tranche timestamp + ├── when the tranche timestamps are not ordered + │ └── it should revert + └── when the tranche timestamps are ordered + ├── when the end time is not in the future + │ └── it should revert + └── when the end time is in the future + ├── when the deposit amount is not equal to the tranche amounts sum + │ └── it should revert + └── when the deposit amount is equal to the tranche amounts sum + ├── given the protocol fee is too high + │ └── it should revert + └── given the protocol fee is not too high + ├── when the broker fee is too high + │ └── it should revert + └── when the broker fee is not too high + ├── when the asset is not a contract + │ └── it should revert + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should record the protocol fee + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupTranchedStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should record the protocol fee + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupTranchedStream} event diff --git a/test/integration/concrete/lockup-tranched/get-range/getRange.t.sol b/test/integration/concrete/lockup-tranched/get-range/getRange.t.sol new file mode 100644 index 000000000..12db5b22a --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-range/getRange.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/libraries/Errors.sol"; +import { LockupTranched } from "src/types/DataTypes.sol"; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +contract GetRange_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { + function test_RevertGiven_Null() external { + uint256 nullStreamId = 1729; + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + lockupTranched.getRange(nullStreamId); + } + + modifier givenNotNull() { + _; + } + + function test_GetRange() external givenNotNull { + uint256 streamId = createDefaultStream(); + LockupTranched.Range memory actualRange = lockupTranched.getRange(streamId); + LockupTranched.Range memory expectedRange = defaults.lockupTranchedRange(); + assertEq(actualRange, expectedRange); + } +} diff --git a/test/integration/concrete/lockup-tranched/get-range/getRange.tree b/test/integration/concrete/lockup-tranched/get-range/getRange.tree new file mode 100644 index 000000000..88dcc9707 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-range/getRange.tree @@ -0,0 +1,5 @@ +getRange.t.sol +├── given the id references a null stream +│ └── it should revert +└── given the id does not reference a null stream + └── it should return the correct range diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol new file mode 100644 index 000000000..63e0d9742 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/libraries/Errors.sol"; +import { LockupTranched } from "src/types/DataTypes.sol"; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +contract GetStream_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { + uint256 internal defaultStreamId; + + function setUp() public virtual override { + LockupTranched_Integration_Concrete_Test.setUp(); + defaultStreamId = createDefaultStream(); + } + + function test_RevertGiven_Null() external { + uint256 nullStreamId = 1729; + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + lockupTranched.getStream(nullStreamId); + } + + modifier givenNotNull() { + _; + } + + function test_GetStream_StatusSettled() external givenNotNull { + vm.warp({ timestamp: defaults.END_TIME() }); + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(defaultStreamId); + LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); + expectedStream.isCancelable = false; + assertEq(actualStream, expectedStream); + } + + modifier givenStatusNotSettled() { + _; + } + + function test_GetStream() external givenNotNull givenStatusNotSettled { + uint256 streamId = createDefaultStream(); + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); + LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); + assertEq(actualStream, expectedStream); + } +} diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.tree b/test/integration/concrete/lockup-tranched/get-stream/getStream.tree new file mode 100644 index 000000000..c3278db89 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-stream/getStream.tree @@ -0,0 +1,8 @@ +getStream.t.sol +├── given the id references a null stream +│ └── it should revert +└── given the id does not reference a null stream + ├── given the stream is settled + │ └── it should adjust the `isCancelable` flag and return the stream + └── given the stream is not settled + └── it should return the stream diff --git a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol new file mode 100644 index 000000000..eaad2a69b --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/libraries/Errors.sol"; +import { LockupTranched } from "src/types/DataTypes.sol"; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +contract GetTranches_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { + function test_RevertGiven_Null() external { + uint256 nullStreamId = 1729; + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + lockupTranched.getTranches(nullStreamId); + } + + modifier givenNotNull() { + _; + } + + function test_GetTranches() external givenNotNull { + uint256 streamId = createDefaultStream(); + LockupTranched.Tranche[] memory actualTranches = lockupTranched.getTranches(streamId); + LockupTranched.Tranche[] memory expectedTranches = defaults.tranches(); + assertEq(actualTranches, expectedTranches, "tranches"); + } +} diff --git a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree new file mode 100644 index 000000000..826ba60fa --- /dev/null +++ b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree @@ -0,0 +1,5 @@ +getTranches.t.sol +├── given the id references a null stream +│ └── it should revert +└── given the id does not reference a null stream + └── it should return the correct tranches diff --git a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol new file mode 100644 index 000000000..a1ae2ed26 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; +import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; + +contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + StreamedAmountOf_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, StreamedAmountOf_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + StreamedAmountOf_Integration_Concrete_Test.setUp(); + } + + function test_StreamedAmountOf_StartTimeInTheFuture() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + { + vm.warp({ timestamp: 0 }); + uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 expectedStreamedAmount = 0; + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } + + function test_StreamedAmountOf_StartTimeInThePresent() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + { + vm.warp({ timestamp: defaults.START_TIME() }); + uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 expectedStreamedAmount = 0; + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } + + modifier givenMultipleTranches() { + _; + } + + function test_StreamedAmountOf_CurrentTimestamp1st() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + givenMultipleTranches + whenStartTimeInThePast + { + // Warp 1 second to the future. + vm.warp({ timestamp: defaults.START_TIME() + 1 seconds }); + + // Run the test. + uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 expectedStreamedAmount = 0; + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } + + modifier givenCurrentTimestampNot1st() { + _; + } + + function test_StreamedAmountOf() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + whenStartTimeInThePast + givenMultipleTranches + givenCurrentTimestampNot1st + { + vm.warp({ timestamp: defaults.END_TIME() - 1 seconds }); + + // Run the test. + uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 expectedStreamedAmount = defaults.tranches()[0].amount + defaults.tranches()[1].amount; + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } +} diff --git a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree new file mode 100644 index 000000000..7c8644b98 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree @@ -0,0 +1,11 @@ +streamedAmountOf.t.sol +└── given the stream's status is "STREAMING" + ├── given the start time is in the future + │ └── it should return zero + ├── given the start time is in the present + │ └── it should return zero + └── given the start time is in the past + ├── given the current timestamp is the 1st in the array + │ └── it should return the correct streamed amount + └── given the current timestamp is not the 1st in the array + └── it should return the correct streamed amount diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol new file mode 100644 index 000000000..033cfedb1 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: UNLICENSED +// solhint-disable max-line-length,no-console,quotes +pragma solidity >=0.8.22 <0.9.0; + +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; +import { console2 } from "forge-std/src/console2.sol"; +import { LibString } from "solady/src/utils/LibString.sol"; +import { StdStyle } from "forge-std/src/StdStyle.sol"; +import { Base64 } from "solady/src/utils/Base64.sol"; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; + +/// @dev Requirements for these tests to work: +/// - The stream id must be 1 +/// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")` +/// - The stream asset must have the DAI symbol +/// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value +/// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as +/// the values hard coded in the tests below +contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { + using LibString for string; + + address internal constant LOCKUP_TRANCHED = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; + uint256 internal defaultStreamId; + + /// @dev To make these tests noninvasive, they are run only when the contract address matches the hard coded value. + modifier skipOnMismatch() { + if (address(lockupTranched) == LOCKUP_TRANCHED) { + _; + } else { + console2.log(StdStyle.yellow('Warning: "lockupTranched.tokenURI" tests skipped due to address mismatch')); + } + } + + function test_RevertGiven_NFTDoesNotExist() external { + uint256 nullStreamId = 1729; + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); + lockupTranched.tokenURI({ tokenId: nullStreamId }); + } + + modifier givenNFTExists() { + defaultStreamId = createDefaultStream(); + vm.warp({ timestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); + _; + } + + /// @dev If you need to update the hard-coded token URI: + /// 1. Use "vm.writeFile" to log the strings to a file. + /// 2. Remember to escape the EOL character \n with \\n. + function test_TokenURI_Decoded() external skipOnMismatch givenNFTExists { + string memory tokenURI = lockupTranched.tokenURI(defaultStreamId); + tokenURI = tokenURI.replace({ search: "data:application/json;base64,", replacement: "" }); + string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); + string memory expectedDecodedTokenURI = + unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Tranched contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; + assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI"); + } + + function test_TokenURI_Full() external skipOnMismatch givenNFTExists { + string memory actualTokenURI = lockupTranched.tokenURI(defaultStreamId); + string memory expectedTokenURI = + "data:application/json;base64,eyJhdHRyaWJ1dGVzIjpbeyJ0cmFpdF90eXBlIjoiQXNzZXQiLCJ2YWx1ZSI6IkRBSSJ9LHsidHJhaXRfdHlwZSI6IlNlbmRlciIsInZhbHVlIjoiMHg2MzMyZTdiMWRlYjFmMWEwYjc3YjJiYjE4YjE0NDMzMGM3MjkxYmNhIn0seyJ0cmFpdF90eXBlIjoiU3RhdHVzIiwidmFsdWUiOiJTdHJlYW1pbmcifV0sImRlc2NyaXB0aW9uIjoiVGhpcyBORlQgcmVwcmVzZW50cyBhIHBheW1lbnQgc3RyZWFtIGluIGEgU2FibGllciBWMiBMb2NrdXAgRHluYW1pYyBjb250cmFjdC4gVGhlIG93bmVyIG9mIHRoaXMgTkZUIGNhbiB3aXRoZHJhdyB0aGUgc3RyZWFtZWQgYXNzZXRzLCB3aGljaCBhcmUgZGVub21pbmF0ZWQgaW4gREFJLlxuXG4tIFN0cmVhbSBJRDogMVxuLSBMb2NrdXAgRHluYW1pYyBBZGRyZXNzOiAweGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDBcbi0gREFJIEFkZHJlc3M6IDB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYlxuXG7imqDvuI8gV0FSTklORzogVHJhbnNmZXJyaW5nIHRoZSBORlQgbWFrZXMgdGhlIG5ldyBvd25lciB0aGUgcmVjaXBpZW50IG9mIHRoZSBzdHJlYW0uIFRoZSBmdW5kcyBhcmUgbm90IGF1dG9tYXRpY2FsbHkgd2l0aGRyYXduIGZvciB0aGUgcHJldmlvdXMgcmVjaXBpZW50LiIsImV4dGVybmFsX3VybCI6Imh0dHBzOi8vc2FibGllci5jb20iLCJuYW1lIjoiU2FibGllciBWMiBMb2NrdXAgRHluYW1pYyAjMSIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0l4TURBd0lpQm9aV2xuYUhROUlqRXdNREFpSUhacFpYZENiM2c5SWpBZ01DQXhNREF3SURFd01EQWlQanh5WldOMElIZHBaSFJvUFNJeE1EQWxJaUJvWldsbmFIUTlJakV3TUNVaUlHWnBiSFJsY2owaWRYSnNLQ05PYjJselpTa2lMejQ4Y21WamRDQjRQU0kzTUNJZ2VUMGlOekFpSUhkcFpIUm9QU0k0TmpBaUlHaGxhV2RvZEQwaU9EWXdJaUJtYVd4c1BTSWpabVptSWlCbWFXeHNMVzl3WVdOcGRIazlJaTR3TXlJZ2NuZzlJalExSWlCeWVUMGlORFVpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExXOXdZV05wZEhrOUlpNHhJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqUWlMejQ4WkdWbWN6NDhZMmx5WTJ4bElHbGtQU0pIYkc5M0lpQnlQU0kxTURBaUlHWnBiR3c5SW5WeWJDZ2pVbUZrYVdGc1IyeHZkeWtpTHo0OFptbHNkR1Z5SUdsa1BTSk9iMmx6WlNJK1BHWmxSbXh2YjJRZ2VEMGlNQ0lnZVQwaU1DSWdkMmxrZEdnOUlqRXdNQ1VpSUdobGFXZG9kRDBpTVRBd0pTSWdabXh2YjJRdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpSUdac2IyOWtMVzl3WVdOcGRIazlJakVpSUhKbGMzVnNkRDBpWm14dmIyUkdhV3hzSWk4K1BHWmxWSFZ5WW5Wc1pXNWpaU0JpWVhObFJuSmxjWFZsYm1ONVBTSXVOQ0lnYm5WdFQyTjBZWFpsY3owaU15SWdjbVZ6ZFd4MFBTSk9iMmx6WlNJZ2RIbHdaVDBpWm5KaFkzUmhiRTV2YVhObElpOCtQR1psUW14bGJtUWdhVzQ5SWs1dmFYTmxJaUJwYmpJOUltWnNiMjlrUm1sc2JDSWdiVzlrWlQwaWMyOW1kQzFzYVdkb2RDSXZQand2Wm1sc2RHVnlQanh3WVhSb0lHbGtQU0pNYjJkdklpQm1hV3hzUFNJalptWm1JaUJtYVd4c0xXOXdZV05wZEhrOUlpNHhJaUJrUFNKdE1UTXpMalUxT1N3eE1qUXVNRE0wWXkwdU1ERXpMREl1TkRFeUxURXVNRFU1TERRdU9EUTRMVEl1T1RJekxEWXVOREF5TFRJdU5UVTRMREV1T0RFNUxUVXVNVFk0TERNdU5ETTVMVGN1T0RnNExEUXVPVGsyTFRFMExqUTBMRGd1TWpZeUxUTXhMakEwTnl3eE1pNDFOalV0TkRjdU5qYzBMREV5TGpVMk9TMDRMamcxT0M0d016WXRNVGN1T0RNNExURXVNamN5TFRJMkxqTXlPQzB6TGpZMk15MDVMamd3TmkweUxqYzJOaTB4T1M0d09EY3ROeTR4TVRNdE1qY3VOVFl5TFRFeUxqYzNPQzB4TXk0NE5ESXRPQzR3TWpVc09TNDBOamd0TWpndU5qQTJMREUyTGpFMU15MHpOUzR5TmpWb01HTXlMakF6TlMweExqZ3pPQ3cwTGpJMU1pMHpMalUwTml3MkxqUTJNeTAxTGpJeU5HZ3dZell1TkRJNUxUVXVOalUxTERFMkxqSXhPQzB5TGpnek5Td3lNQzR6TlRnc05DNHhOeXcwTGpFME15dzFMakExTnl3NExqZ3hOaXc1TGpZME9Td3hNeTQ1TWl3eE15NDNNelJvTGpBek4yTTFMamN6Tml3MkxqUTJNU3d4TlM0ek5UY3RNaTR5TlRNc09TNHpPQzA0TGpRNExEQXNNQzB6TGpVeE5TMHpMalV4TlMwekxqVXhOUzB6TGpVeE5TMHhNUzQwT1MweE1TNDBOemd0TlRJdU5qVTJMVFV5TGpZMk5DMDJOQzQ0TXpjdE5qUXVPRE0zYkM0d05Ea3RMakF6TjJNdE1TNDNNalV0TVM0Mk1EWXRNaTQzTVRrdE15NDRORGN0TWk0M05URXROaTR5TURSb01HTXRMakEwTmkweUxqTTNOU3d4TGpBMk1pMDBMalU0TWl3eUxqY3lOaTAyTGpJeU9XZ3diQzR4T0RVdExqRTBPR2d3WXk0d09Ua3RMakEyTWl3dU1qSXlMUzR4TkRnc0xqTTNMUzR5TlRsb01HTXlMakEyTFRFdU16WXlMRE11T1RVeExUSXVOakl4TERZdU1EUTBMVE11T0RReVF6VTNMamMyTXkwekxqUTNNeXc1Tnk0M05pMHlMak0wTVN3eE1qZ3VOak0zTERFNExqTXpNbU14Tmk0Mk56RXNPUzQ1TkRZdE1qWXVNelEwTERVMExqZ3hNeTB6T0M0Mk5URXNOREF1TVRrNUxUWXVNams1TFRZdU1EazJMVEU0TGpBMk15MHhOeTQzTkRNdE1Ua3VOalk0TFRFNExqZ3hNUzAyTGpBeE5pMDBMakEwTnkweE15NHdOakVzTkM0M056WXROeTQzTlRJc09TNDNOVEZzTmpndU1qVTBMRFk0TGpNM01XTXhMamN5TkN3eExqWXdNU3d5TGpjeE5Dd3pMamcwTERJdU56TTRMRFl1TVRreVdpSXZQanh3WVhSb0lHbGtQU0pHYkc5aGRHbHVaMVJsZUhRaUlHWnBiR3c5SW01dmJtVWlJR1E5SWsweE1qVWdORFZvTnpVd2N6Z3dJREFnT0RBZ09EQjJOelV3Y3pBZ09EQWdMVGd3SURnd2FDMDNOVEJ6TFRnd0lEQWdMVGd3SUMwNE1IWXROelV3Y3pBZ0xUZ3dJRGd3SUMwNE1DSXZQanh5WVdScFlXeEhjbUZrYVdWdWRDQnBaRDBpVW1Ga2FXRnNSMnh2ZHlJK1BITjBiM0FnYjJabWMyVjBQU0l3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RZeExEZzRKU3cwTUNVcElpQnpkRzl3TFc5d1lXTnBkSGs5SWk0MklpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeE1EQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRHOXdMVzl3WVdOcGRIazlJakFpTHo0OEwzSmhaR2xoYkVkeVlXUnBaVzUwUGp4c2FXNWxZWEpIY21Ga2FXVnVkQ0JwWkQwaVUyRnVaRlJ2Y0NJZ2VERTlJakFsSWlCNU1UMGlNQ1VpUGp4emRHOXdJRzltWm5ObGREMGlNQ1VpSUhOMGIzQXRZMjlzYjNJOUltaHpiQ2cyTVN3NE9DVXNOREFsS1NJdlBqeHpkRzl3SUc5bVpuTmxkRDBpTVRBd0pTSWdjM1J2Y0MxamIyeHZjajBpYUhOc0tESXpNQ3d5TVNVc01URWxLU0l2UGp3dmJHbHVaV0Z5UjNKaFpHbGxiblErUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKVFlXNWtRbTkwZEc5dElpQjRNVDBpTVRBd0pTSWdlVEU5SWpFd01DVWlQanh6ZEc5d0lHOW1abk5sZEQwaU1UQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkRzl3TFdOdmJHOXlQU0pvYzJ3b05qRXNPRGdsTERRd0pTa2lMejQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRNU0lnWkhWeVBTSTJjeUlnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJSFpoYkhWbGN6MGlNekFsT3pZd0pUc3hNakFsT3pZd0pUc3pNQ1U3SWk4K1BDOXNhVzVsWVhKSGNtRmthV1Z1ZEQ0OGJHbHVaV0Z5UjNKaFpHbGxiblFnYVdROUlraHZkWEpuYkdGemMxTjBjbTlyWlNJZ1ozSmhaR2xsYm5SVWNtRnVjMlp2Y20wOUluSnZkR0YwWlNnNU1Da2lJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J2Wm1aelpYUTlJalV3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RZeExEZzRKU3cwTUNVcElpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJNE1DVWlJSE4wYjNBdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp4bklHbGtQU0pJYjNWeVoyeGhjM01pUGp4d1lYUm9JR1E5SWswZ05UQXNNell3SUdFZ016QXdMRE13TUNBd0lERXNNU0EyTURBc01DQmhJRE13TUN3ek1EQWdNQ0F4TERFZ0xUWXdNQ3d3SWlCbWFXeHNQU0lqWm1abUlpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d01pSWdjM1J5YjJ0bFBTSjFjbXdvSTBodmRYSm5iR0Z6YzFOMGNtOXJaU2tpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0l2UGp4d1lYUm9JR1E5SW0wMU5qWXNNVFl4TGpJd01YWXROVE11T1RJMFl6QXRNVGt1TXpneUxUSXlMalV4TXkwek55NDFOak10TmpNdU16azRMVFV4TGpFNU9DMDBNQzQzTlRZdE1UTXVOVGt5TFRrMExqazBOaTB5TVM0d056a3RNVFV5TGpVNE55MHlNUzR3TnpsekxURXhNUzQ0TXpnc055NDBPRGN0TVRVeUxqWXdNaXd5TVM0d056bGpMVFF3TGpnNU15d3hNeTQyTXpZdE5qTXVOREV6TERNeExqZ3hOaTAyTXk0ME1UTXNOVEV1TVRrNGRqVXpMamt5TkdNd0xERTNMakU0TVN3eE55NDNNRFFzTXpNdU5ESTNMRFV3TGpJeU15dzBOaTR6T1RSMk1qZzBMamd3T1dNdE16SXVOVEU1TERFeUxqazJMVFV3TGpJeU15d3lPUzR5TURZdE5UQXVNakl6TERRMkxqTTVOSFkxTXk0NU1qUmpNQ3d4T1M0ek9ESXNNakl1TlRJc016Y3VOVFl6TERZekxqUXhNeXcxTVM0eE9UZ3NOREF1TnpZekxERXpMalU1TWl3NU5DNDVOVFFzTWpFdU1EYzVMREUxTWk0Mk1ESXNNakV1TURjNWN6RXhNUzQ0TXpFdE55NDBPRGNzTVRVeUxqVTROeTB5TVM0d056bGpOREF1T0RnMkxURXpMall6Tml3Mk15NHpPVGd0TXpFdU9ERTJMRFl6TGpNNU9DMDFNUzR4T1RoMkxUVXpMamt5TkdNd0xURTNMakU1TmkweE55NDNNRFF0TXpNdU5ETTFMVFV3TGpJeU15MDBOaTQwTURGV01qQTNMall3TTJNek1pNDFNVGt0TVRJdU9UWTNMRFV3TGpJeU15MHlPUzR5TURZc05UQXVNakl6TFRRMkxqUXdNVnB0TFRNME55NDBOaklzTlRjdU56a3piREV6TUM0NU5Ua3NNVE14TGpBeU55MHhNekF1T1RVNUxERXpNUzR3TVROV01qRTRMams1TkZwdE1qWXlMamt5TkM0d01qSjJNall5TGpBeE9Hd3RNVE13TGprek55MHhNekV1TURBMkxERXpNQzQ1TXpjdE1UTXhMakF4TTFvaUlHWnBiR3c5SWlNeE5qRTRNaklpUGp3dmNHRjBhRDQ4Y0c5c2VXZHZiaUJ3YjJsdWRITTlJak0xTUNBek5UQXVNREkySURReE5TNHdNeUF5T0RRdU9UYzRJREk0TlNBeU9EUXVPVGM0SURNMU1DQXpOVEF1TURJMklpQm1hV3hzUFNKMWNtd29JMU5oYm1SQ2IzUjBiMjBwSWk4K1BIQmhkR2dnWkQwaWJUUXhOaTR6TkRFc01qZ3hMamszTldNd0xDNDVNVFF0TGpNMU5Dd3hMamd3T1MweExqQXpOU3d5TGpZNExUVXVOVFF5TERjdU1EYzJMVE15TGpZMk1Td3hNaTQwTlMwMk5TNHlPQ3d4TWk0ME5TMHpNaTQyTWpRc01DMDFPUzQzTXpndE5TNHpOelF0TmpVdU1qZ3RNVEl1TkRVdExqWTRNUzB1T0RjeUxURXVNRE0xTFRFdU56WTNMVEV1TURNMUxUSXVOamdzTUMwdU9URTBMak0xTkMweExqZ3dPQ3d4TGpBek5TMHlMalkzTml3MUxqVTBNaTAzTGpBM05pd3pNaTQyTlRZdE1USXVORFVzTmpVdU1qZ3RNVEl1TkRVc016SXVOakU1TERBc05Ua3VOek00TERVdU16YzBMRFkxTGpJNExERXlMalExTGpZNE1TNDROamNzTVM0d016VXNNUzQzTmpJc01TNHdNelVzTWk0Mk56WmFJaUJtYVd4c1BTSjFjbXdvSTFOaGJtUlViM0FwSWk4K1BIQmhkR2dnWkQwaWJUUTRNUzQwTml3MU1EUXVNVEF4ZGpVNExqUTBPV010TWk0ek5TNDNOeTAwTGpneUxERXVOVEV0Tnk0ek9Td3lMakl6TFRNd0xqTXNPQzQxTkMwM05DNDJOU3d4TXk0NU1pMHhNalF1TURZc01UTXVPVEl0TlRNdU5pd3dMVEV3TVM0eU5DMDJMak16TFRFek1TNDBOeTB4Tmk0eE5uWXROVGd1TkRNNWFESTJNaTQ1TWxvaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkVKdmRIUnZiU2tpTHo0OFpXeHNhWEJ6WlNCamVEMGlNelV3SWlCamVUMGlOVEEwTGpFd01TSWdjbmc5SWpFek1TNDBOaklpSUhKNVBTSXlPQzR4TURnaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkZSdmNDa2lMejQ4WnlCbWFXeHNQU0p1YjI1bElpQnpkSEp2YTJVOUluVnliQ2dqU0c5MWNtZHNZWE56VTNSeWIydGxLU0lnYzNSeWIydGxMV3hwYm1WallYQTlJbkp2ZFc1a0lpQnpkSEp2YTJVdGJXbDBaWEpzYVcxcGREMGlNVEFpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0krUEhCaGRHZ2daRDBpYlRVMk5TNDJOREVzTVRBM0xqSTRZekFzT1M0MU16Y3ROUzQxTml3eE9DNDJNamt0TVRVdU5qYzJMREkyTGprM00yZ3RMakF5TTJNdE9TNHlNRFFzTnk0MU9UWXRNakl1TVRrMExERTBMalUyTWkwek9DNHhPVGNzTWpBdU5Ua3lMVE01TGpVd05Dd3hOQzQ1TXpZdE9UY3VNekkxTERJMExqTTFOUzB4TmpFdU56TXpMREkwTGpNMU5TMDVNQzQwT0N3d0xURTJOeTQ1TkRndE1UZ3VOVGd5TFRFNU9TNDVOVE10TkRRdU9UUTRhQzB1TURJell5MHhNQzR4TVRVdE9DNHpORFF0TVRVdU5qYzJMVEUzTGpRek55MHhOUzQyTnpZdE1qWXVPVGN6TERBdE16a3VOek0xTERrMkxqVTFOQzAzTVM0NU1qRXNNakUxTGpZMU1pMDNNUzQ1TWpGek1qRTFMall5T1N3ek1pNHhPRFVzTWpFMUxqWXlPU3czTVM0NU1qRmFJaTgrUEhCaGRHZ2daRDBpYlRFek5DNHpOaXd4TmpFdU1qQXpZekFzTXprdU56TTFMRGsyTGpVMU5DdzNNUzQ1TWpFc01qRTFMalkxTWl3M01TNDVNakZ6TWpFMUxqWXlPUzB6TWk0eE9EWXNNakUxTGpZeU9TMDNNUzQ1TWpFaUx6NDhiR2x1WlNCNE1UMGlNVE0wTGpNMklpQjVNVDBpTVRZeExqSXdNeUlnZURJOUlqRXpOQzR6TmlJZ2VUSTlJakV3Tnk0eU9DSXZQanhzYVc1bElIZ3hQU0kxTmpVdU5qUWlJSGt4UFNJeE5qRXVNakF6SWlCNE1qMGlOVFkxTGpZMElpQjVNajBpTVRBM0xqSTRJaTgrUEd4cGJtVWdlREU5SWpFNE5DNDFPRFFpSUhreFBTSXlNRFl1T0RJeklpQjRNajBpTVRnMExqVTROU0lnZVRJOUlqVXpOeTQxTnpraUx6NDhiR2x1WlNCNE1UMGlNakU0TGpFNE1TSWdlVEU5SWpJeE9DNHhNVGdpSUhneVBTSXlNVGd1TVRneElpQjVNajBpTlRZeUxqVXpOeUl2UGp4c2FXNWxJSGd4UFNJME9ERXVPREU0SWlCNU1UMGlNakU0TGpFME1pSWdlREk5SWpRNE1TNDRNVGtpSUhreVBTSTFOakl1TkRJNElpOCtQR3hwYm1VZ2VERTlJalV4TlM0ME1UVWlJSGt4UFNJeU1EY3VNelV5SWlCNE1qMGlOVEUxTGpReE5pSWdlVEk5SWpVek55NDFOemtpTHo0OGNHRjBhQ0JrUFNKdE1UZzBMalU0TERVek55NDFPR013TERVdU5EVXNOQzR5Tnl3eE1DNDJOU3d4TWk0d015d3hOUzQwTW1ndU1ESmpOUzQxTVN3ekxqTTVMREV5TGpjNUxEWXVOVFVzTWpFdU5UVXNPUzQwTWl3ek1DNHlNU3c1TGprc056Z3VNRElzTVRZdU1qZ3NNVE14TGpnekxERTJMakk0TERRNUxqUXhMREFzT1RNdU56WXROUzR6T0N3eE1qUXVNRFl0TVRNdU9USXNNaTQzTFM0M05pdzFMakk1TFRFdU5UUXNOeTQzTlMweUxqTTFMRGd1TnpjdE1pNDROeXd4Tmk0d05TMDJMakEwTERJeExqVTJMVGt1TkROb01HTTNMamMyTFRRdU56Y3NNVEl1TURRdE9TNDVOeXd4TWk0d05DMHhOUzQwTWlJdlBqeHdZWFJvSUdROUltMHhPRFF1TlRneUxEUTVNaTQyTlRaakxUTXhMak0xTkN3eE1pNDBPRFV0TlRBdU1qSXpMREk0TGpVNExUVXdMakl5TXl3ME5pNHhORElzTUN3NUxqVXpOaXcxTGpVMk5Dd3hPQzQyTWpjc01UVXVOamMzTERJMkxqazJPV2d1TURJeVl6Z3VOVEF6TERjdU1EQTFMREl3TGpJeE15d3hNeTQwTmpNc016UXVOVEkwTERFNUxqRTFPU3c1TGprNU9Td3pMams1TVN3eU1TNHlOamtzTnk0Mk1Ea3NNek11TlRrM0xERXdMamM0T0N3ek5pNDBOU3c1TGpRd055dzRNaTR4T0RFc01UVXVNREF5TERFek1TNDRNelVzTVRVdU1EQXljemsxTGpNMk15MDFMalU1TlN3eE16RXVPREEzTFRFMUxqQXdNbU14TUM0NE5EY3RNaTQzT1N3eU1DNDROamN0TlM0NU1qWXNNamt1T1RJMExUa3VNelE1TERFdU1qUTBMUzQwTmpjc01pNDBOek10TGprME1pd3pMalkzTXkweExqUXlOQ3d4TkM0ek1qWXROUzQyT1RZc01qWXVNRE0xTFRFeUxqRTJNU3d6TkM0MU1qUXRNVGt1TVRjemFDNHdNakpqTVRBdU1URTBMVGd1TXpReUxERTFMalkzTnkweE55NDBNek1zTVRVdU5qYzNMVEkyTGprMk9Td3dMVEUzTGpVMk1pMHhPQzQ0TmprdE16TXVOalkxTFRVd0xqSXlNeTAwTmk0eE5TSXZQanh3WVhSb0lHUTlJbTB4TXpRdU16WXNOVGt5TGpjeVl6QXNNemt1TnpNMUxEazJMalUxTkN3M01TNDVNakVzTWpFMUxqWTFNaXczTVM0NU1qRnpNakUxTGpZeU9TMHpNaTR4T0RZc01qRTFMall5T1MwM01TNDVNakVpTHo0OGJHbHVaU0I0TVQwaU1UTTBMak0ySWlCNU1UMGlOVGt5TGpjeUlpQjRNajBpTVRNMExqTTJJaUI1TWowaU5UTTRMamM1TnlJdlBqeHNhVzVsSUhneFBTSTFOalV1TmpRaUlIa3hQU0kxT1RJdU56SWlJSGd5UFNJMU5qVXVOalFpSUhreVBTSTFNemd1TnprM0lpOCtQSEJ2Ykhsc2FXNWxJSEJ2YVc1MGN6MGlORGd4TGpneU1pQTBPREV1T1RBeElEUTRNUzQzT1RnZ05EZ3hMamczTnlBME9ERXVOemMxSURRNE1TNDROVFFnTXpVd0xqQXhOU0F6TlRBdU1ESTJJREl4T0M0eE9EVWdNakU0TGpFeU9TSXZQanh3YjJ4NWJHbHVaU0J3YjJsdWRITTlJakl4T0M0eE9EVWdORGd4TGprd01TQXlNVGd1TWpNeElEUTRNUzQ0TlRRZ016VXdMakF4TlNBek5UQXVNREkySURRNE1TNDRNaklnTWpFNExqRTFNaUl2UGp3dlp6NDhMMmMrUEdjZ2FXUTlJbEJ5YjJkeVpYTnpJaUJtYVd4c1BTSWpabVptSWo0OGNtVmpkQ0IzYVdSMGFEMGlNakE0SWlCb1pXbG5hSFE5SWpFd01DSWdabWxzYkMxdmNHRmphWFI1UFNJdU1ETWlJSEo0UFNJeE5TSWdjbms5SWpFMUlpQnpkSEp2YTJVOUlpTm1abVlpSUhOMGNtOXJaUzF2Y0dGamFYUjVQU0l1TVNJZ2MzUnliMnRsTFhkcFpIUm9QU0kwSWk4K1BIUmxlSFFnZUQwaU1qQWlJSGs5SWpNMElpQm1iMjUwTFdaaGJXbHNlVDBpSjBOdmRYSnBaWElnVG1WM0p5eEJjbWxoYkN4dGIyNXZjM0JoWTJVaUlHWnZiblF0YzJsNlpUMGlNakp3ZUNJK1VISnZaM0psYzNNOEwzUmxlSFErUEhSbGVIUWdlRDBpTWpBaUlIazlJamN5SWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krTWpVbFBDOTBaWGgwUGp4bklHWnBiR3c5SW01dmJtVWlQanhqYVhKamJHVWdZM2c5SWpFMk5pSWdZM2s5SWpVd0lpQnlQU0l5TWlJZ2MzUnliMnRsUFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRISnZhMlV0ZDJsa2RHZzlJakV3SWk4K1BHTnBjbU5zWlNCamVEMGlNVFkySWlCamVUMGlOVEFpSUhCaGRHaE1aVzVuZEdnOUlqRXdNREF3SWlCeVBTSXlNaUlnYzNSeWIydGxQU0pvYzJ3b05qRXNPRGdsTERRd0pTa2lJSE4wY205clpTMWtZWE5vWVhKeVlYazlJakV3TURBd0lpQnpkSEp2YTJVdFpHRnphRzltWm5ObGREMGlOelV3TUNJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW5KdmRXNWtJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqVWlJSFJ5WVc1elptOXliVDBpY205MFlYUmxLQzA1TUNraUlIUnlZVzV6Wm05eWJTMXZjbWxuYVc0OUlqRTJOaUExTUNJdlBqd3ZaejQ4TDJjK1BHY2dhV1E5SWxOMFlYUjFjeUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakU0TkNJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBsTjBZWFIxY3p3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l5TUNJZ2VUMGlOeklpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajVUZEhKbFlXMXBibWM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pCYlc5MWJuUWlJR1pwYkd3OUlpTm1abVlpUGp4eVpXTjBJSGRwWkhSb1BTSXhNakFpSUdobGFXZG9kRDBpTVRBd0lpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d015SWdjbmc5SWpFMUlpQnllVDBpTVRVaUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMVzl3WVdOcGRIazlJaTR4SWlCemRISnZhMlV0ZDJsa2RHZzlJalFpTHo0OGRHVjRkQ0I0UFNJeU1DSWdlVDBpTXpRaUlHWnZiblF0Wm1GdGFXeDVQU0luUTI5MWNtbGxjaUJPWlhjbkxFRnlhV0ZzTEcxdmJtOXpjR0ZqWlNJZ1ptOXVkQzF6YVhwbFBTSXlNbkI0SWo1QmJXOTFiblE4TDNSbGVIUStQSFJsZUhRZ2VEMGlNakFpSUhrOUlqY3lJaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1p2Ym5RdGMybDZaVDBpTWpad2VDSStKaU00T0RBMU95QXhNRXM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pFZFhKaGRHbHZiaUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakUxTWlJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBrUjFjbUYwYVc5dVBDOTBaWGgwUGp4MFpYaDBJSGc5SWpJd0lpQjVQU0kzTWlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGlac2REc2dNU0JFWVhrOEwzUmxlSFErUEM5blBqd3ZaR1ZtY3o0OGRHVjRkQ0IwWlhoMExYSmxibVJsY21sdVp6MGliM0IwYVcxcGVtVlRjR1ZsWkNJK1BIUmxlSFJRWVhSb0lITjBZWEowVDJabWMyVjBQU0l0TVRBd0pTSWdhSEpsWmowaUkwWnNiMkYwYVc1blZHVjRkQ0lnWm1sc2JEMGlJMlptWmlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ0SWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGp4aGJtbHRZWFJsSUdGa1pHbDBhWFpsUFNKemRXMGlJR0YwZEhKcFluVjBaVTVoYldVOUluTjBZWEowVDJabWMyVjBJaUJpWldkcGJqMGlNSE1pSUdSMWNqMGlOVEJ6SWlCbWNtOXRQU0l3SlNJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhSdlBTSXhNREFsSWk4K01IaGtZakkxWVRkaU56WTRNekV4WkdVeE1qaGlZbVJoTjJJNE5ESTJZek5tT1dNM05HWXpNalF3SU9LQW9pQlRZV0pzYVdWeUlGWXlJRXh2WTJ0MWNDQkVlVzVoYldsalBDOTBaWGgwVUdGMGFENDhkR1Y0ZEZCaGRHZ2djM1JoY25SUFptWnpaWFE5SWpBbElpQm9jbVZtUFNJalJteHZZWFJwYm1kVVpYaDBJaUJtYVd4c1BTSWpabVptSWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdacGJHd3RiM0JoWTJsMGVUMGlMamdpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krUEdGdWFXMWhkR1VnWVdSa2FYUnBkbVU5SW5OMWJTSWdZWFIwY21saWRYUmxUbUZ0WlQwaWMzUmhjblJQWm1aelpYUWlJR0psWjJsdVBTSXdjeUlnWkhWeVBTSTFNSE1pSUdaeWIyMDlJakFsSWlCeVpYQmxZWFJEYjNWdWREMGlhVzVrWldacGJtbDBaU0lnZEc4OUlqRXdNQ1VpTHo0d2VHUmlNalZoTjJJM05qZ3pNVEZrWlRFeU9HSmlaR0UzWWpnME1qWmpNMlk1WXpjMFpqTXlOREFnNG9DaUlGTmhZbXhwWlhJZ1ZqSWdURzlqYTNWd0lFUjVibUZ0YVdNOEwzUmxlSFJRWVhSb1BqeDBaWGgwVUdGMGFDQnpkR0Z5ZEU5bVpuTmxkRDBpTFRVd0pTSWdhSEpsWmowaUkwWnNiMkYwYVc1blZHVjRkQ0lnWm1sc2JEMGlJMlptWmlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ0SWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGp4aGJtbHRZWFJsSUdGa1pHbDBhWFpsUFNKemRXMGlJR0YwZEhKcFluVjBaVTVoYldVOUluTjBZWEowVDJabWMyVjBJaUJpWldkcGJqMGlNSE1pSUdSMWNqMGlOVEJ6SWlCbWNtOXRQU0l3SlNJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhSdlBTSXhNREFsSWk4K01IZ3dNMkUyWVRnMFkyUTNOakprT1Rjd04yRXlNVFl3TldJMU5EaGhZV0ZpT0RreE5UWXlZV0ZpSU9LQW9pQkVRVWs4TDNSbGVIUlFZWFJvUGp4MFpYaDBVR0YwYUNCemRHRnlkRTltWm5ObGREMGlOVEFsSWlCb2NtVm1QU0lqUm14dllYUnBibWRVWlhoMElpQm1hV3hzUFNJalptWm1JaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqZ2lJR1p2Ym5RdGMybDZaVDBpTWpad2VDSStQR0Z1YVcxaGRHVWdZV1JrYVhScGRtVTlJbk4xYlNJZ1lYUjBjbWxpZFhSbFRtRnRaVDBpYzNSaGNuUlBabVp6WlhRaUlHSmxaMmx1UFNJd2N5SWdaSFZ5UFNJMU1ITWlJR1p5YjIwOUlqQWxJaUJ5WlhCbFlYUkRiM1Z1ZEQwaWFXNWtaV1pwYm1sMFpTSWdkRzg5SWpFd01DVWlMejR3ZURBellUWmhPRFJqWkRjMk1tUTVOekEzWVRJeE5qQTFZalUwT0dGaFlXSTRPVEUxTmpKaFlXSWc0b0NpSUVSQlNUd3ZkR1Y0ZEZCaGRHZytQQzkwWlhoMFBqeDFjMlVnYUhKbFpqMGlJMGRzYjNjaUlHWnBiR3d0YjNCaFkybDBlVDBpTGpraUx6NDhkWE5sSUdoeVpXWTlJaU5IYkc5M0lpQjRQU0l4TURBd0lpQjVQU0l4TURBd0lpQm1hV3hzTFc5d1lXTnBkSGs5SWk0NUlpOCtQSFZ6WlNCb2NtVm1QU0lqVEc5bmJ5SWdlRDBpTVRjd0lpQjVQU0l4TnpBaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb0xqWXBJaTgrUEhWelpTQm9jbVZtUFNJalNHOTFjbWRzWVhOeklpQjRQU0l4TlRBaUlIazlJamt3SWlCMGNtRnVjMlp2Y20wOUluSnZkR0YwWlNneE1Da2lJSFJ5WVc1elptOXliUzF2Y21sbmFXNDlJalV3TUNBMU1EQWlMejQ4ZFhObElHaHlaV1k5SWlOUWNtOW5jbVZ6Y3lJZ2VEMGlNVFEwSWlCNVBTSTNPVEFpTHo0OGRYTmxJR2h5WldZOUlpTlRkR0YwZFhNaUlIZzlJak0yT0NJZ2VUMGlOemt3SWk4K1BIVnpaU0JvY21WbVBTSWpRVzF2ZFc1MElpQjRQU0kxTmpnaUlIazlJamM1TUNJdlBqeDFjMlVnYUhKbFpqMGlJMFIxY21GMGFXOXVJaUI0UFNJM01EUWlJSGs5SWpjNU1DSXZQand2YzNablBnPT0ifQ=="; + assertEq(actualTokenURI, expectedTokenURI, "token URI"); + } +} diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree new file mode 100644 index 000000000..6a58d7e09 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree @@ -0,0 +1,5 @@ +tokenURI.t.sol +├── given the NFT does not exist +│ └── it should revert +└── given the NFT exists + └── it should return the correct token URI diff --git a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol new file mode 100644 index 000000000..1867a4e06 --- /dev/null +++ b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; +import { WithdrawableAmountOf_Integration_Concrete_Test } from + "../../lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol"; + +contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WithdrawableAmountOf_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WithdrawableAmountOf_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WithdrawableAmountOf_Integration_Concrete_Test.setUp(); + } + + function test_WithdrawableAmountOf_StartTimeInThePresent() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + { + vm.warp({ timestamp: defaults.START_TIME() }); + uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + uint128 expectedWithdrawableAmount = 0; + assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); + } + + modifier givenStartTimeInThePast() { + _; + } + + function test_WithdrawableAmountOf_NoPreviousWithdrawals() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + givenStartTimeInThePast + { + // Simulate the passage of time. + vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); + + // Run the test. + uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + uint128 expectedWithdrawableAmount = defaults.tranches()[0].amount; + assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); + } + + modifier whenWithWithdrawals() { + _; + } + + function test_WithdrawableAmountOf() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusStreaming + givenStartTimeInThePast + whenWithWithdrawals + { + // Simulate the passage of time. + vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); + + // Make the withdrawal. + lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); + + // Run the test. + uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + + uint128 expectedWithdrawableAmount = defaults.tranches()[0].amount - defaults.CLIFF_AMOUNT(); + assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); + } +} diff --git a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree new file mode 100644 index 000000000..fe3ff45ef --- /dev/null +++ b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree @@ -0,0 +1,9 @@ +withdrawableAmountOf.t.sol +└── given the stream's status is "STREAMING" + ├── given the start time is in the present + │ └── it should return zero + └── given the start time is in the past + ├── given there are no previous withdrawals + │ └── it should return the correct withdrawable amount + └── given there are previous withdrawals + └── it should return the correct withdrawable amount diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol deleted file mode 100644 index 6b90a2054..000000000 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// solhint-disable max-line-length -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; -import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; -import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; - -abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, Withdraw_Integration_Shared_Test { - function setUp() public virtual override(Integration_Test, Withdraw_Integration_Shared_Test) { - Withdraw_Integration_Shared_Test.setUp(); - } - - modifier givenDifferentSenderAndRecipient() { - _; - } - - function test_WithdrawHooks_CallerUnknown() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - address unknownCaller = address(0xCAFE); - - // Create the stream with sender and recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Make `unknownCaller` the caller in this test. - changePrank({ msgSender: unknownCaller }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); - } - - function test_WithdrawHooks_CallerApprovedOperator() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with sender and recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodRecipient) }); - lockup.approve({ to: users.operator, tokenId: streamId }); - - // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, users.operator, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); - } - - function test_WithdrawHooks_CallerSender() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with sender and recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Make the sender the caller in this test. - changePrank({ msgSender: address(goodSender) }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect 1 call to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Expect 0 calls to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), - count: 0 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); - } - - function test_WithdrawHooks_CallerRecipient() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with sender and recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Make the recipient the caller in this test. - changePrank({ msgSender: address(goodRecipient) }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect 0 calls to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) - ), - count: 0 - }); - - // Expect 1 call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); - } - - modifier givenSameSenderAndRecipient() { - _; - } - - function test_WithdrawHooks_SenderHook_CallerUnknown() external givenSenderContract givenSameSenderAndRecipient { - address unknownCaller = address(0xCAFE); - - // Create the stream with recipient which is same as the sender contract. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); - - // Make unknownCaller the caller in this test. - changePrank({ msgSender: unknownCaller }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodSender), withdrawAmount) - ), - count: 1 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); - } - - function test_WithdrawHooks_SenderHook_CallerApprovedOperator() - external - givenSenderContract - givenSameSenderAndRecipient - { - // Create the stream with recipient which is same as the sender contract. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); - - // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodSender) }); - lockup.approve({ to: users.operator, tokenId: streamId }); - - // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodSender), withdrawAmount) - ), - count: 1 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); - } - - function test_WithdrawHooks_SenderHook_CallerSender() external givenSenderContract givenSameSenderAndRecipient { - // Create the stream with the sender as the recipient. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); - - // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodSender) }); - - // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect 0 calls to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodSender), withdrawAmount) - ), - count: 0 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); - } -} diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree deleted file mode 100644 index 79a896aa2..000000000 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree +++ /dev/null @@ -1,21 +0,0 @@ -withdrawHooks.t.sol -├── given the recipient is different than the sender -│ ├── when the caller is unknown -│ │ ├── it should make one hook call to the sender -│ │ └── it should make one hook call to the recipient -│ ├── when the caller is an approved third party -│ │ ├── it should make one hook call to the sender -│ │ └── it should make one hook call to the recipient -│ ├── when the caller is the sender -│ │ ├── it should not make any hook call to the sender -│ │ └── it should make one hook call to the recipient -│ └── when the caller is the recipient -│ ├── it should make one hook call to the sender -│ └── it should not make any hook call to the recipient -└── given the recipient is same as the sender - ├── when the caller is unknown - │ └── it should make one hook call to the sender - ├── when the caller is an approved third party - │ └── it should make one hook call to the sender - └── when the caller is the sender - └── it should not make any hook call to the sender diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index a5247649f..9e4b9002e 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -16,6 +16,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr Withdraw_Integration_Shared_Test.setUp(); } + /*////////////////////////////////////////////////////////////////////////// + TESTS + //////////////////////////////////////////////////////////////////////////*/ + function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = @@ -193,6 +197,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(defaultStreamId, users.sender); } + modifier givenSenderContract() { + _; + } + function test_Withdraw_SenderDoesNotImplementHook() external whenNotDelegateCalled @@ -308,7 +316,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(streamId, address(goodSender)); } - function test_Withdraw_CallerUnknown() + function test_Withdraw_CallerUnknownAddress() external whenNotDelegateCalled givenNotNull @@ -451,6 +459,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerSender(defaultStreamId, users.recipient); } + modifier givenRecipientContract() { + _; + } + function test_Withdraw_RecipientDoesNotImplementHook() external whenNotDelegateCalled diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index e2cad95c0..0801e2cdd 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -30,7 +30,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenDepositAmountNotZero whenSegmentCountNotZero { - segmentCount = _bound(segmentCount, defaults.MAX_SEGMENT_COUNT() + 1 seconds, defaults.MAX_SEGMENT_COUNT() * 10); + segmentCount = _bound(segmentCount, defaults.MAX_COUNT() + 1 seconds, defaults.MAX_COUNT() * 10); LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) diff --git a/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol new file mode 100644 index 000000000..deb66a89b --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; +import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; + +import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; +import { Integration_Test } from "../../Integration.t.sol"; +import { Cancel_Integration_Fuzz_Test } from "../lockup/cancel.t.sol"; +import { CancelMultiple_Integration_Fuzz_Test } from "../lockup/cancelMultiple.t.sol"; +import { GetWithdrawnAmount_Integration_Fuzz_Test } from "../lockup/getWithdrawnAmount.t.sol"; +import { RefundableAmountOf_Integration_Fuzz_Test } from "../lockup/refundableAmountOf.t.sol"; +import { WithdrawMax_Integration_Fuzz_Test } from "../lockup/withdrawMax.t.sol"; +import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "../lockup/withdrawMaxAndTransfer.t.sol"; +import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultiple.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED ABSTRACT TEST +//////////////////////////////////////////////////////////////////////////*/ + +/// @notice Common testing logic needed across {SablierV2LockupTranched} integration fuzz tests. +abstract contract LockupTranched_Integration_Fuzz_Test is Integration_Test, LockupTranched_Integration_Shared_Test { + function setUp() public virtual override(Integration_Test, LockupTranched_Integration_Shared_Test) { + // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is + // allowed in Solidity, and {Base_Test-setUp} will only be called once. + Integration_Test.setUp(); + LockupTranched_Integration_Shared_Test.setUp(); + + // Cast the LockupTranched contract as {ISablierV2Base} and {ISablierV2Lockup}. + base = ISablierV2Base(lockupTranched); + lockup = ISablierV2Lockup(lockupTranched); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Cancel_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + Cancel_Integration_Fuzz_Test +{ + function setUp() public virtual override(LockupTranched_Integration_Fuzz_Test, Cancel_Integration_Fuzz_Test) { + LockupTranched_Integration_Fuzz_Test.setUp(); + Cancel_Integration_Fuzz_Test.setUp(); + } +} + +contract CancelMultiple_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + CancelMultiple_Integration_Fuzz_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, CancelMultiple_Integration_Fuzz_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + CancelMultiple_Integration_Fuzz_Test.setUp(); + } +} + +contract RefundableAmountOf_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + RefundableAmountOf_Integration_Fuzz_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, RefundableAmountOf_Integration_Fuzz_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + RefundableAmountOf_Integration_Fuzz_Test.setUp(); + } +} + +contract GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + GetWithdrawnAmount_Integration_Fuzz_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, GetWithdrawnAmount_Integration_Fuzz_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + GetWithdrawnAmount_Integration_Fuzz_Test.setUp(); + } +} + +contract WithdrawMax_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + WithdrawMax_Integration_Fuzz_Test +{ + function setUp() public virtual override(LockupTranched_Integration_Fuzz_Test, WithdrawMax_Integration_Fuzz_Test) { + LockupTranched_Integration_Fuzz_Test.setUp(); + WithdrawMax_Integration_Fuzz_Test.setUp(); + } +} + +contract WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + WithdrawMaxAndTransfer_Integration_Fuzz_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, WithdrawMaxAndTransfer_Integration_Fuzz_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + WithdrawMaxAndTransfer_Integration_Fuzz_Test.setUp(); + } +} + +contract WithdrawMultiple_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + WithdrawMultiple_Integration_Fuzz_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, WithdrawMultiple_Integration_Fuzz_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + WithdrawMultiple_Integration_Fuzz_Test.setUp(); + } +} diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol new file mode 100644 index 000000000..48f82ad3e --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup-tranched/createWithDurations.t.sol"; +import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; + +contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + CreateWithDurations_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, CreateWithDurations_Integration_Shared_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + CreateWithDurations_Integration_Shared_Test.setUp(); + } + + struct Vars { + uint256 actualNextStreamId; + address actualNFTOwner; + uint256 actualProtocolRevenues; + Lockup.Status actualStatus; + Lockup.CreateAmounts createAmounts; + uint256 expectedNextStreamId; + address expectedNFTOwner; + uint256 expectedProtocolRevenues; + Lockup.Status expectedStatus; + address funder; + uint128 initialProtocolRevenues; + bool isCancelable; + bool isSettled; + LockupTranched.Tranche[] tranchesWithTimestamps; + uint128 totalAmount; + } + + function testFuzz_CreateWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) + external + whenNotDelegateCalled + whenLoopCalculationsDoNotOverflowBlockGasLimit + whenDurationsNotZero + whenTimestampsCalculationsDoNotOverflow + { + vm.assume(tranches.length != 0); + + // Fuzz the durations. + Vars memory vars; + fuzzTrancheDurations(tranches); + + // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(tranches); + + // Make the Sender the stream's funder (recall that the Sender is the default caller). + vars.funder = users.sender; + + // Load the initial protocol revenues. + vars.initialProtocolRevenues = lockupTranched.protocolRevenues(dai); + + // Mint enough assets to the fuzzed funder. + deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); + + // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + expectCallToTransferFrom({ + from: vars.funder, + to: address(lockupTranched), + value: vars.createAmounts.deposit + vars.createAmounts.protocolFee + }); + + // Expect the broker fee to be paid to the broker, if not zero. + if (vars.createAmounts.brokerFee > 0) { + expectCallToTransferFrom({ from: vars.funder, to: users.broker, value: vars.createAmounts.brokerFee }); + } + + // Create the range struct. + vars.tranchesWithTimestamps = getTranchesWithTimestamps(tranches); + LockupTranched.Range memory range = LockupTranched.Range({ + start: getBlockTimestamp(), + end: vars.tranchesWithTimestamps[vars.tranchesWithTimestamps.length - 1].timestamp + }); + + // Expect the relevant event to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit CreateLockupTranchedStream({ + streamId: streamId, + funder: vars.funder, + sender: users.sender, + recipient: users.recipient, + amounts: vars.createAmounts, + asset: dai, + cancelable: true, + transferable: true, + tranches: vars.tranchesWithTimestamps, + range: range, + broker: users.broker + }); + + // Create the stream. + LockupTranched.CreateWithDurations memory params = defaults.createWithDurationsLT(); + params.tranches = tranches; + params.totalAmount = vars.totalAmount; + params.transferable = true; + lockupTranched.createWithDurations(params); + + // Check if the stream is settled. It is possible for a Lockup Tranched stream to settle at the time of creation + // because some tranche amounts can be zero. + vars.isSettled = lockupTranched.refundableAmountOf(streamId) == 0; + vars.isCancelable = vars.isSettled ? false : true; + + // Assert that the stream has been created. + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); + assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); + assertEq(actualStream.asset, dai, "asset"); + assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); + assertEq(actualStream.isTransferable, true, "isTransferable"); + assertEq(actualStream.isDepleted, false, "isDepleted"); + assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.tranches, vars.tranchesWithTimestamps, "tranches"); + assertEq(actualStream.sender, users.sender, "sender"); + assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.wasCanceled, false, "wasCanceled"); + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(streamId); + vars.expectedStatus = vars.isSettled ? Lockup.Status.SETTLED : Lockup.Status.STREAMING; + assertEq(vars.actualStatus, vars.expectedStatus); + + // Assert that the next stream id has been bumped. + vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.expectedNextStreamId = streamId + 1; + assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); + + // Assert that the protocol fee has been recorded. + vars.actualProtocolRevenues = lockupTranched.protocolRevenues(dai); + vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; + assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); + + // Assert that the NFT has been minted. + vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + vars.expectedNFTOwner = users.recipient; + assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); + } +} diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol new file mode 100644 index 000000000..d1b3ed1f7 --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { stdError } from "forge-std/src/StdError.sol"; + +import { Errors } from "src/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-tranched/createWithTimestamps.t.sol"; +import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; + +contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + CreateWithTimestamps_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, CreateWithTimestamps_Integration_Shared_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + CreateWithTimestamps_Integration_Shared_Test.setUp(); + } + + function testFuzz_RevertWhen_TrancheCountTooHigh(uint256 trancheCount) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + { + trancheCount = _bound(trancheCount, defaults.MAX_COUNT() + 1 seconds, defaults.MAX_COUNT() * 10); + LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) + ); + createDefaultStreamWithTranches(tranches); + } + + function testFuzz_RevertWhen_TrancheAmountsSumOverflows( + uint128 amount0, + uint128 amount1 + ) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + { + amount0 = boundUint128(amount0, MAX_UINT128 / 2 + 1, MAX_UINT128); + amount1 = boundUint128(amount0, MAX_UINT128 / 2 + 1, MAX_UINT128); + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].amount = amount0; + tranches[1].amount = amount1; + vm.expectRevert(stdError.arithmeticError); + createDefaultStreamWithTranches(tranches); + } + + function testFuzz_RevertWhen_StartTimeNotLessThanFirstTrancheTimestamp(uint40 firstTimestamp) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + { + firstTimestamp = boundUint40(firstTimestamp, 0, defaults.START_TIME()); + + // Change the timestamp of the first tranche. + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].timestamp = firstTimestamp; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + defaults.START_TIME(), + tranches[0].timestamp + ) + ); + + // Create the stream. + createDefaultStreamWithTranches(tranches); + } + + function testFuzz_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum(uint128 depositDiff) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + { + depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); + + // Disable both the protocol and the broker fee so that they don't interfere with the calculations. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); + UD60x18 brokerFee = ZERO; + changePrank({ msgSender: users.sender }); + + // Adjust the default deposit amount. + uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); + uint128 depositAmount = defaultDepositAmount + depositDiff; + + // Prepare the params. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: brokerFee }); + params.totalAmount = depositAmount; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + depositAmount, + defaultDepositAmount + ) + ); + + // Create the stream. + lockupTranched.createWithTimestamps(params); + } + + function testFuzz_RevertWhen_ProtocolFeeTooHigh(UD60x18 protocolFee) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + { + protocolFee = _bound(protocolFee, MAX_FEE + ud(1), MAX_UD60x18); + + // Set the protocol fee. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); + changePrank({ msgSender: users.sender }); + + // Run the test. + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) + ); + createDefaultStream(); + } + + function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + { + vm.assume(broker.account != address(0)); + broker.fee = _bound(broker.fee, MAX_FEE + ud(1), MAX_UD60x18); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_FEE)); + createDefaultStreamWithBroker(broker); + } + + struct Vars { + uint256 actualNextStreamId; + address actualNFTOwner; + uint256 actualProtocolRevenues; + Lockup.Status actualStatus; + Lockup.CreateAmounts createAmounts; + uint256 expectedNextStreamId; + address expectedNFTOwner; + uint256 expectedProtocolRevenues; + Lockup.Status expectedStatus; + bool isCancelable; + bool isSettled; + uint128 totalAmount; + } + + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - All possible permutations for the funder, sender, recipient, and broker + /// - Multiple values for the tranche amounts, exponents, and timestamps + /// - Cancelable and not cancelable + /// - Start time in the past + /// - Start time in the present + /// - Start time in the future + /// - Start time equal and not equal to the first tranche timestamp + /// - Multiple values for the broker fee, including zero + /// - Multiple values for the protocol fee, including zero + function testFuzz_CreateWithTimestamps( + address funder, + LockupTranched.CreateWithTimestamps memory params, + UD60x18 protocolFee + ) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenTrancheCountNotZero + whenTrancheCountNotTooHigh + whenTrancheAmountsSumDoesNotOverflow + whenStartTimeLessThanFirstTrancheTimestamp + whenTrancheTimestampsOrdered + whenEndTimeInTheFuture + whenDepositAmountEqualToTrancheAmountsSum + givenProtocolFeeNotTooHigh + whenBrokerFeeNotTooHigh + whenAssetContract + whenAssetERC20 + { + vm.assume(funder != address(0) && params.recipient != address(0) && params.broker.account != address(0)); + vm.assume(params.tranches.length != 0); + params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + protocolFee = _bound(protocolFee, 0, MAX_FEE); + params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + params.transferable = true; + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(params.tranches, params.startTime); + + // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + Vars memory vars; + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128, + tranches: params.tranches, + protocolFee: protocolFee, + brokerFee: params.broker.fee + }); + + // Set the fuzzed protocol fee. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); + + // Make the fuzzed funder the caller in the rest of this test. + changePrank(funder); + + // Mint enough assets to the fuzzed funder. + deal({ token: address(dai), to: funder, give: vars.totalAmount }); + + // Approve {SablierV2LockupTranched} to transfer the assets from the fuzzed funder. + dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + + // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + expectCallToTransferFrom({ + from: funder, + to: address(lockupTranched), + value: vars.createAmounts.deposit + vars.createAmounts.protocolFee + }); + + // Expect the broker fee to be paid to the broker, if not zero. + if (vars.createAmounts.brokerFee > 0) { + expectCallToTransferFrom({ from: funder, to: params.broker.account, value: vars.createAmounts.brokerFee }); + } + + // Expect the relevant event to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + LockupTranched.Range memory range = LockupTranched.Range({ + start: params.startTime, + end: params.tranches[params.tranches.length - 1].timestamp + }); + emit CreateLockupTranchedStream({ + streamId: streamId, + funder: funder, + sender: params.sender, + recipient: params.recipient, + amounts: vars.createAmounts, + asset: dai, + cancelable: params.cancelable, + transferable: params.transferable, + tranches: params.tranches, + range: range, + broker: params.broker.account + }); + + // Create the stream. + lockupTranched.createWithTimestamps( + LockupTranched.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: vars.totalAmount, + asset: dai, + cancelable: params.cancelable, + transferable: params.transferable, + startTime: params.startTime, + tranches: params.tranches, + broker: params.broker + }) + ); + + // Check if the stream is settled. It is possible for a Lockup Tranched stream to settle at the time of creation + // because some tranche amounts can be zero. + vars.isSettled = (lockupTranched.getDepositedAmount(streamId) - lockupTranched.streamedAmountOf(streamId)) == 0; + vars.isCancelable = vars.isSettled ? false : params.cancelable; + + // Assert that the stream has been created. + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); + assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); + assertEq(actualStream.asset, dai, "asset"); + assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); + assertEq(actualStream.isTransferable, true, "isTransferable"); + assertEq(actualStream.isDepleted, false, "isStream"); + assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.sender, params.sender, "sender"); + assertEq(actualStream.tranches, params.tranches, "tranches"); + assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.wasCanceled, false, "wasCanceled"); + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(streamId); + if (params.startTime > getBlockTimestamp()) { + vars.expectedStatus = Lockup.Status.PENDING; + } else if (vars.isSettled) { + vars.expectedStatus = Lockup.Status.SETTLED; + } else { + vars.expectedStatus = Lockup.Status.STREAMING; + } + assertEq(vars.actualStatus, vars.expectedStatus); + + // Assert that the next stream id has been bumped. + vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.expectedNextStreamId = streamId + 1; + assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); + + // Assert that the protocol fee has been recorded. + vars.actualProtocolRevenues = lockupTranched.protocolRevenues(dai); + vars.expectedProtocolRevenues = vars.createAmounts.protocolFee; + assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); + + // Assert that the NFT has been minted. + vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + vars.expectedNFTOwner = params.recipient; + assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); + } +} diff --git a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol new file mode 100644 index 000000000..47a5b9650 --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ZERO } from "@prb/math/src/UD60x18.sol"; +import { Broker, LockupTranched } from "src/types/DataTypes.sol"; + +import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; +import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; + +contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + StreamedAmountOf_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, StreamedAmountOf_Integration_Shared_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + StreamedAmountOf_Integration_Shared_Test.setUp(); + + // Disable the protocol fee so that it doesn't interfere with the calculations. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); + changePrank({ msgSender: users.sender }); + } + + modifier givenMultipleTranches() { + _; + } + + modifier whenCurrentTimestampNot1st() { + _; + } + + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - End time in the past + /// - End time in the present + /// - End time in the future + /// - Multiple deposit amounts + /// - Status streaming + /// - Status settled + function testFuzz_StreamedAmountOf_Calculation( + LockupTranched.Tranche[] memory tranches, + uint40 timeJump + ) + external + givenNotNull + givenStreamHasNotBeenCanceled + whenStartTimeInThePast + givenMultipleTranches + whenCurrentTimestampNot1st + { + vm.assume(tranches.length > 1); + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(tranches, defaults.START_TIME()); + + // Fuzz the tranche amounts. + (uint128 totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128, + tranches: tranches, + protocolFee: ZERO, + brokerFee: ZERO + }); + + // Bound the time jump. + uint40 firstTrancheDuration = tranches[1].timestamp - tranches[0].timestamp; + uint40 totalDuration = tranches[tranches.length - 1].timestamp - defaults.START_TIME(); + timeJump = boundUint40(timeJump, firstTrancheDuration, totalDuration + 100 seconds); + + // Mint enough assets to the Sender. + deal({ token: address(dai), to: users.sender, give: totalAmount }); + + // Create the stream with the fuzzed tranches. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: ZERO }); + params.tranches = tranches; + params.totalAmount = totalAmount; + uint256 streamId = lockupTranched.createWithTimestamps(params); + + // Simulate the passage of time. + uint40 currentTime = defaults.START_TIME() + timeJump; + vm.warp({ timestamp: currentTime }); + + // Run the test. + uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(streamId); + uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(currentTime, tranches, totalAmount); + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } + + /// @dev The streamed amount must never go down over time. + function testFuzz_StreamedAmountOf_Monotonicity( + LockupTranched.Tranche[] memory tranches, + uint40 timeWarp0, + uint40 timeWarp1 + ) + external + givenNotNull + givenStreamHasNotBeenCanceled + whenStartTimeInThePast + givenMultipleTranches + whenCurrentTimestampNot1st + { + vm.assume(tranches.length > 1); + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(tranches, defaults.START_TIME()); + + // Fuzz the tranche amounts. + (uint128 totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128, + tranches: tranches, + protocolFee: ZERO, + brokerFee: ZERO + }); + + // Bound the time warps. + uint40 firstTrancheDuration = tranches[1].timestamp - tranches[0].timestamp; + uint40 totalDuration = tranches[tranches.length - 1].timestamp - defaults.START_TIME(); + timeWarp0 = boundUint40(timeWarp0, firstTrancheDuration, totalDuration - 1); + timeWarp1 = boundUint40(timeWarp1, timeWarp0, totalDuration); + + // Mint enough assets to the Sender. + deal({ token: address(dai), to: users.sender, give: totalAmount }); + + // Create the stream with the fuzzed tranches. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: ZERO }); + params.tranches = tranches; + params.totalAmount = totalAmount; + uint256 streamId = lockupTranched.createWithTimestamps(params); + + // Warp to the future for the first time. + vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); + + // Calculate the streamed amount at this midpoint in time. + uint128 streamedAmount0 = lockupTranched.streamedAmountOf(streamId); + + // Warp to the future for the second time. + vm.warp({ timestamp: defaults.START_TIME() + timeWarp1 }); + + // Assert that this streamed amount is greater than or equal to the previous streamed amount. + uint128 streamedAmount1 = lockupTranched.streamedAmountOf(streamId); + assertGte(streamedAmount1, streamedAmount0, "streamedAmount"); + } +} diff --git a/test/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/integration/fuzz/lockup-tranched/withdraw.t.sol new file mode 100644 index 000000000..d278e8e40 --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; +import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; + +/// @dev This contract complements the tests in {Withdraw_Integration_Fuzz_Test} by testing the withdraw function +/// against +/// streams created with fuzzed tranches. +contract Withdraw_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + Withdraw_Integration_Fuzz_Test +{ + function setUp() public virtual override(LockupTranched_Integration_Fuzz_Test, Withdraw_Integration_Fuzz_Test) { + LockupTranched_Integration_Fuzz_Test.setUp(); + Withdraw_Integration_Fuzz_Test.setUp(); + } + + struct Params { + LockupTranched.Tranche[] tranches; + uint256 timeJump; + address to; + } + + struct Vars { + Lockup.Status actualStatus; + uint256 actualWithdrawnAmount; + Lockup.CreateAmounts createAmounts; + Lockup.Status expectedStatus; + uint256 expectedWithdrawnAmount; + bool isDepleted; + bool isSettled; + address funder; + uint256 streamId; + uint128 totalAmount; + uint40 totalDuration; + uint128 withdrawAmount; + uint128 withdrawableAmount; + } + + function testFuzz_Withdraw_TrancheFuzzing(Params memory params) + external + whenNotDelegateCalled + givenNotNull + whenToNonZeroAddress + whenWithdrawAmountNotZero + whenNoOverdraw + { + vm.assume(params.tranches.length != 0); + vm.assume(params.to != address(0)); + + // Make the Sender the stream's funder (recall that the Sender is the default caller). + Vars memory vars; + vars.funder = users.sender; + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(params.tranches, defaults.START_TIME()); + + // Fuzz the tranche amounts. + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(params.tranches); + + // Bound the time jump. + vars.totalDuration = params.tranches[params.tranches.length - 1].timestamp - defaults.START_TIME(); + params.timeJump = _bound(params.timeJump, 1 seconds, vars.totalDuration + 100 seconds); + + // Mint enough assets to the funder. + deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); + + // Make the Sender the caller. + changePrank({ msgSender: users.sender }); + + // Create the stream with the fuzzed tranches. + LockupTranched.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLT(); + createParams.totalAmount = vars.totalAmount; + createParams.tranches = params.tranches; + + vars.streamId = lockupTranched.createWithTimestamps(createParams); + + // Simulate the passage of time. + vm.warp({ timestamp: defaults.START_TIME() + params.timeJump }); + + // Query the withdrawable amount. + vars.withdrawableAmount = lockupTranched.withdrawableAmountOf(vars.streamId); + + // Halt the test if the withdraw amount is zero. + if (vars.withdrawableAmount == 0) { + return; + } + + // Bound the withdraw amount. + vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); + + // Make the Recipient the caller. + changePrank({ msgSender: users.recipient }); + + // Expect the assets to be transferred to the fuzzed `to` address. + expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockupTranched) }); + emit WithdrawFromLockupStream({ streamId: vars.streamId, to: params.to, asset: dai, amount: vars.withdrawAmount }); + vm.expectEmit({ emitter: address(lockupTranched) }); + emit MetadataUpdate({ _tokenId: vars.streamId }); + + // Make the withdrawal. + lockupTranched.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); + + // Check if the stream is depleted or settled. It is possible for the stream to be just settled + // and not depleted because the withdraw amount is fuzzed. + vars.isDepleted = vars.withdrawAmount == vars.createAmounts.deposit; + vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + + // Assert that the stream's status is correct. + vars.actualStatus = lockupTranched.statusOf(vars.streamId); + if (vars.isDepleted) { + vars.expectedStatus = Lockup.Status.DEPLETED; + } else if (vars.isSettled) { + vars.expectedStatus = Lockup.Status.SETTLED; + } else { + vars.expectedStatus = Lockup.Status.STREAMING; + } + assertEq(vars.actualStatus, vars.expectedStatus); + + // Assert that the withdrawn amount has been updated. + vars.actualWithdrawnAmount = lockupTranched.getWithdrawnAmount(vars.streamId); + vars.expectedWithdrawnAmount = vars.withdrawAmount; + assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "withdrawnAmount"); + } +} diff --git a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol new file mode 100644 index 000000000..6fed27a48 --- /dev/null +++ b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ZERO } from "@prb/math/src/UD60x18.sol"; + +import { Broker, LockupTranched } from "src/types/DataTypes.sol"; + +import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; +import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; + +contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is + LockupTranched_Integration_Fuzz_Test, + WithdrawableAmountOf_Integration_Shared_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Fuzz_Test, WithdrawableAmountOf_Integration_Shared_Test) + { + LockupTranched_Integration_Fuzz_Test.setUp(); + WithdrawableAmountOf_Integration_Shared_Test.setUp(); + + // Disable the protocol fee so that it doesn't interfere with the calculations. + changePrank({ msgSender: users.admin }); + comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); + changePrank({ msgSender: users.sender }); + } + + modifier whenStartTimeInThePast() { + _; + } + + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - End time in the past + /// - End time in the present + /// - End time in the future + /// - Status streaming + /// - Status settled + function testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40 timeJump) external whenStartTimeInThePast { + timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); + + // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with + // the calculations. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: ZERO }); + params.totalAmount = defaults.DEPOSIT_AMOUNT(); + uint256 streamId = lockupTranched.createWithTimestamps(params); + + // Simulate the passage of time. + uint40 currentTime = defaults.START_TIME() + timeJump; + vm.warp({ timestamp: currentTime }); + + // Run the test. + uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); + uint128 expectedWithdrawableAmount = + calculateStreamedAmountForTranches(currentTime, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); + } + + modifier whenWithWithdrawals() { + _; + } + + /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: + /// + /// - End time in the past + /// - End time in the present + /// - End time in the future + /// - Multiple withdraw amounts + /// - Status streaming + /// - Status settled + /// - Status depleted + /// - Withdraw amount equal to deposited amount and not + function testFuzz_WithdrawableAmountOf( + uint40 timeJump, + uint128 withdrawAmount + ) + external + whenStartTimeInThePast + whenWithWithdrawals + { + timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); + + // Define the current time. + uint40 currentTime = defaults.START_TIME() + timeJump; + + // Bound the withdraw amount. + uint128 streamedAmount = + calculateStreamedAmountForTranches(currentTime, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); + + // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with + // the calculations. + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + params.broker = Broker({ account: address(0), fee: ZERO }); + params.totalAmount = defaults.DEPOSIT_AMOUNT(); + uint256 streamId = lockupTranched.createWithTimestamps(params); + + // Simulate the passage of time. + vm.warp({ timestamp: currentTime }); + + // Make the withdrawal. + lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + + // Run the test. + uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); + uint128 expectedWithdrawableAmount = streamedAmount - withdrawAmount; + assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); + } +} diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 08ee66844..b67bf3aa4 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -147,19 +147,4 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh params.totalAmount = totalAmount; streamId = lockupDynamic.createWithTimestamps(params); } - - /// @dev Creates the default stream with the provided sender and recipient. - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - override - returns (uint256 streamId) - { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - params.recipient = recipient; - streamId = lockupDynamic.createWithTimestamps(params); - } } diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index eed455052..1fe86adbf 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -113,19 +113,4 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha params.totalAmount = totalAmount; streamId = lockupLinear.createWithTimestamps(params); } - - /// @dev Creates the default stream with the provided sender and recipient. - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - override - returns (uint256 streamId) - { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - params.recipient = recipient; - streamId = lockupLinear.createWithTimestamps(params); - } } diff --git a/test/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/integration/shared/lockup-tranched/LockupTranched.t.sol new file mode 100644 index 000000000..69725a5e0 --- /dev/null +++ b/test/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { Broker, LockupTranched } from "src/types/DataTypes.sol"; + +import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; + +/// @notice Common testing logic needed across {SablierV2LockupTranched} integration tests. +abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_Shared_Test { + struct CreateParams { + LockupTranched.CreateWithDurations createWithDurations; + LockupTranched.CreateWithTimestamps createWithTimestamps; + } + + /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. + /// See https://github.com/foundry-rs/foundry/issues/4762. + CreateParams private _params; + + function setUp() public virtual override { + Lockup_Integration_Shared_Test.setUp(); + + _params.createWithDurations.sender = users.sender; + _params.createWithDurations.recipient = users.recipient; + _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); + _params.createWithDurations.asset = dai; + _params.createWithDurations.cancelable = true; + _params.createWithDurations.transferable = true; + _params.createWithDurations.broker = defaults.broker(); + + _params.createWithTimestamps.sender = users.sender; + _params.createWithTimestamps.recipient = users.recipient; + _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); + _params.createWithTimestamps.asset = dai; + _params.createWithTimestamps.cancelable = true; + _params.createWithTimestamps.transferable = true; + _params.createWithTimestamps.startTime = defaults.START_TIME(); + _params.createWithTimestamps.broker = defaults.broker(); + + // See https://github.com/ethereum/solidity/issues/12783 + LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + for (uint256 i = 0; i < defaults.TRANCHE_COUNT(); ++i) { + _params.createWithDurations.tranches.push(tranchesWithDurations[i]); + _params.createWithTimestamps.tranches.push(tranches[i]); + } + } + + /// @dev Creates the default stream. + function createDefaultStream() internal override returns (uint256 streamId) { + streamId = lockupTranched.createWithTimestamps(_params.createWithTimestamps); + } + + /// @dev Creates the default stream with the provided asset. + function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.asset = asset; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided broker. + function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.broker = broker; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with durations. + function createDefaultStreamWithDurations() internal returns (uint256 streamId) { + streamId = lockupTranched.createWithDurations(_params.createWithDurations); + } + + /// @dev Creates the default stream with the provided durations. + function createDefaultStreamWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) + internal + returns (uint256 streamId) + { + LockupTranched.CreateWithDurations memory params = _params.createWithDurations; + params.tranches = tranches; + streamId = lockupTranched.createWithDurations(params); + } + + /// @dev Creates the default stream with the provided end time. + function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.tranches[2].timestamp = endTime; + + // Ensure the timestamps are arranged in ascending order. + if (params.tranches[2].timestamp <= params.tranches[1].timestamp) { + params.tranches[1].timestamp = params.tranches[2].timestamp - 1; + } + if (params.tranches[1].timestamp <= params.tranches[0].timestamp) { + params.tranches[0].timestamp = params.tranches[1].timestamp - 1; + } + + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates a stream that will not be cancelable. + function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.cancelable = false; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the NFT transfer disabled. + function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.transferable = false; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided range. + function createDefaultStreamWithRange(LockupTranched.Range memory range) internal returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.startTime = range.start; + params.tranches[1].timestamp = range.end; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided recipient. + function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.recipient = recipient; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided tranches. + function createDefaultStreamWithTranches(LockupTranched.Tranche[] memory tranches) + internal + returns (uint256 streamId) + { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.tranches = tranches; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided sender. + function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided start time.. + function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.startTime = startTime; + streamId = lockupTranched.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided total amount. + function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.totalAmount = totalAmount; + streamId = lockupTranched.createWithTimestamps(params); + } +} diff --git a/test/integration/shared/lockup-tranched/createWithDurations.t.sol b/test/integration/shared/lockup-tranched/createWithDurations.t.sol new file mode 100644 index 000000000..ec4609379 --- /dev/null +++ b/test/integration/shared/lockup-tranched/createWithDurations.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; + +contract CreateWithDurations_Integration_Shared_Test is LockupTranched_Integration_Shared_Test { + uint256 internal streamId; + + function setUp() public virtual override { + streamId = lockupTranched.nextStreamId(); + } + + modifier whenNotDelegateCalled() { + _; + } + + modifier whenLoopCalculationsDoNotOverflowBlockGasLimit() { + _; + } + + modifier whenDurationsNotZero() { + _; + } + + modifier whenTimestampsCalculationsDoNotOverflow() { + _; + } +} diff --git a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol new file mode 100644 index 000000000..a5dede843 --- /dev/null +++ b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; + +contract CreateWithTimestamps_Integration_Shared_Test is LockupTranched_Integration_Shared_Test { + uint256 internal streamId; + + function setUp() public virtual override { + streamId = lockupTranched.nextStreamId(); + } + + modifier whenNotDelegateCalled() { + _; + } + + modifier whenRecipientNonZeroAddress() { + _; + } + + modifier whenDepositAmountNotZero() { + _; + } + + modifier whenTrancheCountNotZero() { + _; + } + + modifier whenTrancheCountNotTooHigh() { + _; + } + + modifier whenTrancheAmountsSumDoesNotOverflow() { + _; + } + + modifier whenStartTimeLessThanFirstTrancheTimestamp() { + _; + } + + modifier whenTrancheTimestampsOrdered() { + _; + } + + modifier whenEndTimeInTheFuture() { + _; + } + + modifier whenDepositAmountEqualToTrancheAmountsSum() { + _; + } + + modifier givenProtocolFeeNotTooHigh() { + _; + } + + modifier whenBrokerFeeNotTooHigh() { + _; + } + + modifier whenAssetContract() { + _; + } + + modifier whenAssetERC20() { + _; + } +} diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 9864d3f26..8fd00072c 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -50,11 +50,6 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal virtual returns (uint256 streamId); - /// @dev Creates the default stream with recipient as the sender. - function createDefaultStreamToSender(address sender) internal virtual returns (uint256 streamId) { - return createDefaultStreamWithUsers(sender, sender); - } - /// @dev Creates the default stream with the provided address. function createDefaultStreamWithAsset(IERC20 asset) internal virtual returns (uint256 streamId); @@ -75,13 +70,4 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the provided total amount. function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided sender and recipient. - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - virtual - returns (uint256 streamId); } diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 86a1c25d5..69fc8cb11 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -51,12 +51,4 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ modifier whenStreamHasNotBeenCanceled() { _; } - - modifier givenSenderContract() { - _; - } - - modifier givenRecipientContract() { - _; - } } diff --git a/test/invariant/Invariant.t.sol b/test/invariant/Invariant.t.sol index f94d792bb..283d28e17 100644 --- a/test/invariant/Invariant.t.sol +++ b/test/invariant/Invariant.t.sol @@ -32,14 +32,11 @@ abstract contract Invariant_Test is Base_Test, StdInvariant { function setUp() public virtual override { Base_Test.setUp(); - // Deploy V2 Core. - deployCoreConditionally(); - // Deploy the handlers. timestampStore = new TimestampStore(); comptrollerHandler = new ComptrollerHandler({ asset_: dai, comptroller_: comptroller, timestampStore_: timestampStore }); - vm.prank({ msgSender: users.admin }); + changePrank(users.admin); comptroller.transferAdmin(address(comptrollerHandler)); // Label the handlers. diff --git a/test/invariant/LockupTranched.t.sol b/test/invariant/LockupTranched.t.sol new file mode 100644 index 000000000..27ed3f778 --- /dev/null +++ b/test/invariant/LockupTranched.t.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; + +import { Lockup_Invariant_Test } from "./Lockup.t.sol"; +import { LockupTranchedCreateHandler } from "./handlers/LockupTranchedCreateHandler.sol"; +import { LockupTranchedHandler } from "./handlers/LockupTranchedHandler.sol"; + +/// @dev Invariant tests for {SablierV2LockupTranched}. +contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + LockupTranchedHandler internal tranchedHandler; + LockupTranchedCreateHandler internal tranchedCreateHandler; + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + Lockup_Invariant_Test.setUp(); + + // Deploy the LockupTranched handlers. + tranchedHandler = new LockupTranchedHandler({ + asset_: dai, + timestampStore_: timestampStore, + lockupStore_: lockupStore, + lockupTranched_: lockupTranched + }); + tranchedCreateHandler = new LockupTranchedCreateHandler({ + asset_: dai, + timestampStore_: timestampStore, + lockupStore_: lockupStore, + comptroller_: comptroller, + lockupTranched_: lockupTranched + }); + + // Label the contracts. + vm.label({ account: address(tranchedHandler), newLabel: "LockupTranchedHandler" }); + vm.label({ account: address(tranchedCreateHandler), newLabel: "LockupTranchedCreateHandler" }); + + // Cast the LockupTranched contract and handler. + lockup = lockupTranched; + lockupHandler = tranchedHandler; + + // Target the LockupTranched handlers for invariant testing. + targetContract(address(tranchedHandler)); + targetContract(address(tranchedCreateHandler)); + + // Prevent these contracts from being fuzzed as `msg.sender`. + excludeSender(address(tranchedHandler)); + excludeSender(address(tranchedCreateHandler)); + } + + /*////////////////////////////////////////////////////////////////////////// + INVARIANTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev The deposited amount must not be zero. + function invariant_DepositedAmountNotZero() external useCurrentTimestamp { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + LockupTranched.StreamLT memory stream = lockupTranched.getStream(streamId); + assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); + } + } + + /// @dev The end time cannot be zero because it must be greater than the start time (which can be zero). + function invariant_EndTimeNotZero() external useCurrentTimestamp { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + LockupTranched.StreamLT memory stream = lockupTranched.getStream(streamId); + assertNotEq(stream.endTime, 0, "Invariant violated: end time zero"); + } + } + + /// @dev Settled streams must not appear as cancelable in {SablierV2LockupTranched.getStream}. + function invariant_StatusSettled_GetStream() external { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockupTranched.statusOf(streamId) == Lockup.Status.SETTLED) { + assertFalse( + lockupTranched.getStream(streamId).isCancelable, + "Invariant violation: stream returned by getStream() is cancelable" + ); + } + } + } + + /// @dev Unordered tranche timestamps are not allowed. + function invariant_TrancheTimestampsOrdered() external useCurrentTimestamp { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + LockupTranched.Tranche[] memory tranches = lockupTranched.getTranches(streamId); + uint40 previousTimestamp = tranches[0].timestamp; + for (uint256 j = 1; j < tranches.length; ++j) { + assertGt(tranches[j].timestamp, previousTimestamp, "Invariant violated: tranche timestamps not ordered"); + previousTimestamp = tranches[j].timestamp; + } + } + } +} diff --git a/test/invariant/handlers/BaseHandler.sol b/test/invariant/handlers/BaseHandler.sol index 9e204065c..2fc68c335 100644 --- a/test/invariant/handlers/BaseHandler.sol +++ b/test/invariant/handlers/BaseHandler.sol @@ -87,8 +87,7 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev Makes the provided sender the caller. modifier useNewSender(address sender) { - vm.startPrank(sender); + changePrank(sender); _; - vm.stopPrank(); } } diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index 53b4bdcc0..7ff5527e4 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -49,9 +49,8 @@ abstract contract LockupHandler is BaseHandler { modifier useAdmin() { address admin = lockup.admin(); - vm.startPrank(admin); + changePrank(admin); _; - vm.stopPrank(); } /// @dev Picks a random stream from the store. @@ -69,17 +68,15 @@ abstract contract LockupHandler is BaseHandler { modifier useFuzzedStreamRecipient() { uint256 lastStreamId = lockupStore.lastStreamId(); currentRecipient = lockupStore.recipients(currentStreamId); - vm.startPrank(currentRecipient); + changePrank(currentRecipient); _; - vm.stopPrank(); } modifier useFuzzedStreamSender() { uint256 lastStreamId = lockupStore.lastStreamId(); currentSender = lockupStore.senders(currentStreamId); - vm.startPrank(currentSender); + changePrank(currentSender); _; - vm.stopPrank(); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/invariant/handlers/LockupTranchedCreateHandler.sol new file mode 100644 index 000000000..faf3aa438 --- /dev/null +++ b/test/invariant/handlers/LockupTranchedCreateHandler.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { LockupTranched } from "src/types/DataTypes.sol"; + +import { LockupStore } from "../stores/LockupStore.sol"; +import { TimestampStore } from "../stores/TimestampStore.sol"; +import { BaseHandler } from "./BaseHandler.sol"; + +/// @dev This contract is a complement of {LockupTranchedHandler}. The goal is to bias the invariant calls +/// toward the lockup functions (especially the create stream functions) by creating multiple handlers for +/// the lockup contracts. +contract LockupTranchedCreateHandler is BaseHandler { + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + ISablierV2Comptroller public comptroller; + LockupStore public lockupStore; + ISablierV2LockupTranched public lockupTranched; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor( + IERC20 asset_, + TimestampStore timestampStore_, + LockupStore lockupStore_, + ISablierV2Comptroller comptroller_, + ISablierV2LockupTranched lockupTranched_ + ) + BaseHandler(asset_, timestampStore_) + { + lockupStore = lockupStore_; + comptroller = comptroller_; + lockupTranched = lockupTranched_; + } + + /*////////////////////////////////////////////////////////////////////////// + HANDLER FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurations( + uint256 timeJumpSeed, + LockupTranched.CreateWithDurations memory params + ) + public + instrument("createWithDurations") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + if (lockupStore.lastStreamId() > MAX_STREAM_COUNT) { + return; + } + + // The protocol doesn't allow empty tranche arrays. + if (params.tranches.length == 0) { + return; + } + + // Bound the broker fee. + params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + + // Fuzz the durations. + fuzzTrancheDurations(params.tranches); + + // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + (params.totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: 1_000_000_000e18, + tranches: params.tranches, + protocolFee: comptroller.protocolFees(asset), + brokerFee: params.broker.fee + }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierV2LockupTranched} to spend the assets. + asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockupTranched.createWithDurations(params); + + // Store the stream id. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithTimestamps( + uint256 timeJumpSeed, + LockupTranched.CreateWithTimestamps memory params + ) + public + instrument("createWithTimestamps") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + if (lockupStore.lastStreamId() >= MAX_STREAM_COUNT) { + return; + } + + // The protocol doesn't allow empty tranche arrays. + if (params.tranches.length == 0) { + return; + } + + params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(params.tranches, params.startTime); + + // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + (params.totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: 1_000_000_000e18, + tranches: params.tranches, + protocolFee: comptroller.protocolFees(asset), + brokerFee: params.broker.fee + }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierV2LockupTranched} to spend the assets. + asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockupTranched.createWithTimestamps(params); + + // Store the stream id. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } +} diff --git a/test/invariant/handlers/LockupTranchedHandler.sol b/test/invariant/handlers/LockupTranchedHandler.sol new file mode 100644 index 000000000..ab62a23fa --- /dev/null +++ b/test/invariant/handlers/LockupTranchedHandler.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; + +import { LockupStore } from "../stores/LockupStore.sol"; +import { TimestampStore } from "../stores/TimestampStore.sol"; +import { LockupHandler } from "./LockupHandler.sol"; + +/// @dev This contract and not {SablierV2LockupTranched} is exposed to Foundry for invariant testing. The point is +/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. +contract LockupTranchedHandler is LockupHandler { + constructor( + IERC20 asset_, + TimestampStore timestampStore_, + LockupStore lockupStore_, + ISablierV2LockupTranched lockupTranched_ + ) + LockupHandler(asset_, timestampStore_, lockupStore_, lockupTranched_) + { } +} diff --git a/test/unit/shared/Adminable.t.sol b/test/unit/shared/Adminable.t.sol index bb8fcdd2d..4136fe729 100644 --- a/test/unit/shared/Adminable.t.sol +++ b/test/unit/shared/Adminable.t.sol @@ -10,7 +10,7 @@ abstract contract Adminable_Unit_Shared_Test is Base_Test { function setUp() public virtual override { Base_Test.setUp(); deployConditionally(); - vm.startPrank({ msgSender: users.admin }); + changePrank({ msgSender: users.admin }); } /// @dev Conditionally deploys {AdminableMock} normally or from a source precompiled with `--via-ir`. diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 05e6761b2..7f9601642 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -5,7 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; import { PRBTest } from "@prb/test/src/PRBTest.sol"; -import { Lockup, LockupDynamic, LockupLinear } from "../../src/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; abstract contract Assertions is PRBTest, PRBMathAssertions { /*////////////////////////////////////////////////////////////////////////// @@ -14,6 +14,8 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { event LogNamedArray(string key, LockupDynamic.Segment[] segments); + event LogNamedArray(string key, LockupTranched.Tranche[] tranches); + event LogNamedUint128(string key, uint128 value); event LogNamedUint40(string key, uint40 value); @@ -68,6 +70,20 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); } + /// @dev Compares two {LockupTranched.Stream} struct entities. + function assertEq(LockupTranched.StreamLT memory a, LockupTranched.StreamLT memory b) internal { + assertEq(a.asset, b.asset, "asset"); + assertEq(a.endTime, b.endTime, "endTime"); + assertEq(a.isCancelable, b.isCancelable, "isCancelable"); + assertEq(a.isDepleted, b.isDepleted, "isDepleted"); + assertEq(a.isTransferable, b.isTransferable, "isTransferable"); + assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.sender, b.sender, "sender"); + assertEq(a.startTime, b.startTime, "startTime"); + assertEq(a.tranches, b.tranches, "tranches"); + assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); + } + /// @dev Compares two {LockupLinear.Range} struct entities. function assertEq(LockupLinear.Range memory a, LockupLinear.Range memory b) internal { assertEqUint40(a.cliff, b.cliff, "range.cliff"); @@ -81,6 +97,12 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { assertEqUint40(a.start, b.start, "range.start"); } + /// @dev Compares two {LockupTranched.Range} struct entities. + function assertEq(LockupTranched.Range memory a, LockupTranched.Range memory b) internal { + assertEqUint40(a.end, b.end, "range.end"); + assertEqUint40(a.start, b.start, "range.start"); + } + /// @dev Compares two {LockupDynamic.Segment[]} arrays. function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { @@ -99,6 +121,30 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { } } + /// @dev Compares two {LockupTranched.Tranche[]} arrays. + function assertEq(LockupTranched.Tranche[] memory a, LockupTranched.Tranche[] memory b) internal { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit Log("Error: a == b not satisfied [LockupTranched.Tranche[]]"); + emit LogNamedArray(" Left", b); + emit LogNamedArray(" Right", a); + fail(); + } + } + + /// @dev Compares two `LockupTranched.Tranche[]` arrays. + function assertEq( + LockupTranched.Tranche[] memory a, + LockupTranched.Tranche[] memory b, + string memory err + ) + internal + { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit LogNamedString("Error", err); + assertEq(a, b); + } + } + /// @dev Compares two {Lockup.Status} enum values. function assertEq(Lockup.Status a, Lockup.Status b) internal { assertEq(uint256(a), uint256(b), "status"); diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index e27ad1b68..828e1ff88 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -9,7 +9,11 @@ import { BaseScript } from "script/Base.s.sol"; contract BaseScript_Test is PRBTest { using Strings for uint256; - BaseScript internal baseScript = new BaseScript(); + BaseScript internal baseScript; + + function setUp() public { + baseScript = new BaseScript(); + } function test_ConstructCreate2Salt() public { string memory chainId = block.chainid.toString(); diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index abbf8562c..20d4ff0ca 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -6,7 +6,7 @@ import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uin import { SD59x18 } from "@prb/math/src/SD59x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { LockupDynamic } from "../../src/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; import { Defaults } from "./Defaults.sol"; @@ -112,4 +112,35 @@ abstract contract Calculations { return uint128(streamedAmountSd.intoUint256()); } } + + /// @dev Helper function that replicates the logic of {SablierV2LockupTranched._calculateStreamedAmount}. + function calculateStreamedAmountForTranches( + uint40 currentTime, + LockupTranched.Tranche[] memory tranches, + uint128 depositAmount + ) + internal + pure + returns (uint128) + { + if (currentTime >= tranches[tranches.length - 1].timestamp) { + return depositAmount; + } + + // Sum the amounts in all tranches that precede the current time. + uint128 streamedAmount = tranches[0].amount; + uint40 currentTrancheTimestamp = tranches[1].timestamp; + uint256 index = 1; + + // Using unchecked arithmetic is safe because the tranches amounts sum equal to total amount at this point. + unchecked { + while (currentTrancheTimestamp <= currentTime) { + streamedAmount += tranches[index].amount; + index += 1; + currentTrancheTimestamp = tranches[index].timestamp; + } + } + + return streamedAmount; + } } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 7fad153ec..39ad671fc 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -2,10 +2,10 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD2x18, ud2x18 } from "@prb/math/src/UD2x18.sol"; +import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { Broker, Lockup, LockupDynamic, LockupLinear } from "../../src/types/DataTypes.sol"; +import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; import { Constants } from "./Constants.sol"; import { Users } from "./Types.sol"; @@ -23,7 +23,7 @@ contract Defaults is Constants { uint40 public constant CLIFF_DURATION = 2500 seconds; uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - uint256 public constant MAX_SEGMENT_COUNT = 300; + uint256 public constant MAX_COUNT = 500; uint40 public immutable MAX_SEGMENT_DURATION; UD60x18 public constant PROTOCOL_FEE = UD60x18.wrap(0.001e18); // 0.1% uint128 public constant PROTOCOL_FEE_AMOUNT = 10.040160642570281124e18; // 0.1% of total amount @@ -32,6 +32,7 @@ contract Defaults is Constants { uint40 public immutable START_TIME; uint128 public constant TOTAL_AMOUNT = 10_040.160642570281124497e18; // deposit / (1 - fee) uint40 public constant TOTAL_DURATION = 10_000 seconds; + uint256 public TRANCHE_COUNT; uint128 public constant WITHDRAW_AMOUNT = 2600e18; uint40 public immutable WARP_26_PERCENT; // 26% of the way through the stream @@ -46,8 +47,9 @@ contract Defaults is Constants { START_TIME = uint40(MAY_1_2023) + 2 days; CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; - MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); + MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_COUNT); SEGMENT_COUNT = 2; + TRANCHE_COUNT = 3; WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; } @@ -127,21 +129,24 @@ contract Defaults is Constants { }); } - function maxSegments() public view returns (LockupDynamic.Segment[] memory maxSegments_) { - uint128 amount = DEPOSIT_AMOUNT / uint128(MAX_SEGMENT_COUNT); - UD2x18 exponent = ud2x18(2.71e18); + function lockupTranchedRange() public view returns (LockupTranched.Range memory) { + return LockupTranched.Range({ start: START_TIME, end: END_TIME }); + } - // Generate a bunch of segments with the same amount, same exponent, and with timestamps evenly spread apart. - maxSegments_ = new LockupDynamic.Segment[](MAX_SEGMENT_COUNT); - for (uint40 i = 0; i < MAX_SEGMENT_COUNT; ++i) { - maxSegments_[i] = ( - LockupDynamic.Segment({ - amount: amount, - exponent: exponent, - timestamp: START_TIME + MAX_SEGMENT_DURATION * (i + 1) - }) - ); - } + function lockupTranchedStream() public view returns (LockupTranched.StreamLT memory) { + return LockupTranched.StreamLT({ + amounts: lockupAmounts(), + asset: asset, + endTime: END_TIME, + isCancelable: true, + isDepleted: false, + isStream: true, + isTransferable: true, + sender: users.sender, + startTime: START_TIME, + tranches: tranches(), + wasCanceled: false + }); } function segments() public view returns (LockupDynamic.Segment[] memory segments_) { @@ -177,6 +182,24 @@ contract Defaults is Constants { ); } + function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = new LockupTranched.Tranche[](3); + tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: START_TIME + CLIFF_DURATION }); + tranches_[1] = LockupTranched.Tranche({ amount: 100e18, timestamp: WARP_26_PERCENT }); + tranches_[2] = LockupTranched.Tranche({ amount: 7400e18, timestamp: START_TIME + TOTAL_DURATION }); + } + + function tranchesWithDurations() + public + pure + returns (LockupTranched.TrancheWithDuration[] memory tranchesWithDurations_) + { + tranchesWithDurations_ = new LockupTranched.TrancheWithDuration[](3); + tranchesWithDurations_[0] = LockupTranched.TrancheWithDuration({ amount: 2500e18, duration: 2500 seconds }); + tranchesWithDurations_[1] = LockupTranched.TrancheWithDuration({ amount: 100e18, duration: 100 seconds }); + tranchesWithDurations_[2] = LockupTranched.TrancheWithDuration({ amount: 7400e18, duration: 7400 seconds }); + } + /*////////////////////////////////////////////////////////////////////////// PARAMS //////////////////////////////////////////////////////////////////////////*/ @@ -207,6 +230,19 @@ contract Defaults is Constants { }); } + function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { + return LockupTranched.CreateWithDurations({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, + asset: asset, + cancelable: true, + transferable: true, + tranches: tranchesWithDurations(), + broker: broker() + }); + } + function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { return LockupDynamic.CreateWithTimestamps({ sender: users.sender, @@ -233,4 +269,18 @@ contract Defaults is Constants { broker: broker() }); } + + function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { + return LockupTranched.CreateWithTimestamps({ + sender: users.sender, + recipient: users.recipient, + totalAmount: TOTAL_AMOUNT, + asset: asset, + cancelable: true, + transferable: true, + startTime: START_TIME, + tranches: tranches(), + broker: broker() + }); + } } diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index 063196565..da78d2267 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -6,6 +6,7 @@ import { StdCheats } from "forge-std/src/StdCheats.sol"; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; abstract contract DeployOptimized is StdCheats { @@ -51,6 +52,24 @@ abstract contract DeployOptimized is StdCheats { ); } + /// @dev Deploys {SablierV2LockupTranched} from an optimized source compiled with `--via-ir`. + function deployOptimizedLockupTranched( + address initialAdmin, + ISablierV2Comptroller comptroller_, + ISablierV2NFTDescriptor nftDescriptor_, + uint256 maxTrancheCount + ) + internal + returns (ISablierV2LockupTranched) + { + return ISablierV2LockupTranched( + deployCode( + "out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json", + abi.encode(initialAdmin, address(comptroller_), address(nftDescriptor_), maxTrancheCount) + ) + ); + } + /// @dev Deploys {SablierV2NFTDescriptor} from an optimized source compiled with `--via-ir`. function deployOptimizedNFTDescriptor() internal returns (ISablierV2NFTDescriptor) { return @@ -59,13 +78,15 @@ abstract contract DeployOptimized is StdCheats { function deployOptimizedCore( address initialAdmin, - uint256 maxSegmentCount + uint256 maxSegmentCount, + uint256 maxTrancheCount ) internal returns ( ISablierV2Comptroller comptroller_, ISablierV2LockupDynamic lockupDynamic_, ISablierV2LockupLinear lockupLinear_, + ISablierV2LockupTranched lockupTranched_, ISablierV2NFTDescriptor nftDescriptor_ ) { @@ -73,5 +94,6 @@ abstract contract DeployOptimized is StdCheats { nftDescriptor_ = deployOptimizedNFTDescriptor(); lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, comptroller_, nftDescriptor_, maxSegmentCount); lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, comptroller_, nftDescriptor_); + lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, comptroller_, nftDescriptor_, maxTrancheCount); } } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 13b51883a..314f99ea6 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -6,7 +6,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { Lockup, LockupDynamic, LockupLinear } from "../../src/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. abstract contract Events { @@ -101,4 +101,22 @@ abstract contract Events { LockupLinear.Range range, address broker ); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + event CreateLockupTranchedStream( + uint256 streamId, + address funder, + address indexed sender, + address indexed recipient, + Lockup.CreateAmounts amounts, + IERC20 indexed asset, + bool cancelable, + bool transferable, + LockupTranched.Tranche[] tranches, + LockupTranched.Range range, + address broker + ); } diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index dc61affb1..8528f743f 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { UD60x18, ud, uUNIT } from "@prb/math/src/UD60x18.sol"; -import { Lockup, LockupDynamic } from "../../src/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; import { Constants } from "./Constants.sol"; import { Defaults } from "./Defaults.sol"; @@ -15,6 +15,10 @@ abstract contract Fuzzers is Constants, Utils { Defaults private defaults = new Defaults(); + /*////////////////////////////////////////////////////////////////////////// + LOCKUP-DYNAMIC + //////////////////////////////////////////////////////////////////////////*/ + /// @dev Just like {fuzzDynamicStreamAmounts} but with defaults. function fuzzDynamicStreamAmounts(LockupDynamic.Segment[] memory segments) internal @@ -89,9 +93,8 @@ abstract contract Fuzzers is Constants, Utils { // Fuzz the other segment amounts by bounding from 0. unchecked { for (uint256 i = 1; i < segmentCount; ++i) { - uint128 segmentAmount = boundUint128(segments[i].amount, 0, maxSegmentAmount); - segments[i].amount = segmentAmount; - estimatedDepositAmount += segmentAmount; + segments[i].amount = boundUint128(segments[i].amount, 0, maxSegmentAmount); + estimatedDepositAmount += segments[i].amount; } } @@ -116,14 +119,14 @@ abstract contract Fuzzers is Constants, Utils { } /// @dev Fuzzes the durations. - function fuzzSegmentDurations(LockupDynamic.SegmentWithDuration[] memory segments) internal pure { + function fuzzSegmentDurations(LockupDynamic.SegmentWithDuration[] memory segments) internal view { unchecked { // Precompute the first segment duration. segments[0].duration = uint40(_bound(segments[0].duration, 1, 100)); // Bound the durations so that none is zero and the calculations don't overflow. uint256 durationCount = segments.length; - uint40 maxDuration = (MAX_UNIX_TIMESTAMP - segments[0].duration) / uint40(durationCount); + uint40 maxDuration = (MAX_UNIX_TIMESTAMP - getBlockTimestamp()) / uint40(durationCount); for (uint256 i = 1; i < durationCount; ++i) { segments[i].duration = boundUint40(segments[i].duration, 1, maxDuration); } @@ -158,4 +161,151 @@ abstract contract Fuzzers is Constants, Utils { segments[i].timestamp = uint40(timestamp); } } + + /*////////////////////////////////////////////////////////////////////////// + LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. + function fuzzTranchedStreamAmounts(LockupTranched.Tranche[] memory tranches) + internal + view + returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) + { + (totalAmount, createAmounts) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128, + tranches: tranches, + protocolFee: defaults.PROTOCOL_FEE(), + brokerFee: defaults.BROKER_FEE() + }); + } + + /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. + function fuzzTranchedStreamAmounts(LockupTranched.TrancheWithDuration[] memory tranches) + internal + view + returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) + { + LockupTranched.Tranche[] memory tranchesWithTimestamps = getTranchesWithTimestamps(tranches); + (totalAmount, createAmounts) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128, + tranches: tranchesWithTimestamps, + protocolFee: defaults.PROTOCOL_FEE(), + brokerFee: defaults.BROKER_FEE() + }); + for (uint256 i = 0; i < tranchesWithTimestamps.length; ++i) { + tranches[i].amount = tranchesWithTimestamps[i].amount; + } + } + + /// @dev Fuzzes the tranche amounts and calculates the create amounts (total, deposit, protocol fee, and broker + /// fee). + function fuzzTranchedStreamAmounts( + uint128 upperBound, + LockupTranched.TrancheWithDuration[] memory tranches, + UD60x18 protocolFee, + UD60x18 brokerFee + ) + internal + view + returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) + { + LockupTranched.Tranche[] memory tranchesWithTimestamps = getTranchesWithTimestamps(tranches); + (totalAmount, createAmounts) = + fuzzTranchedStreamAmounts(upperBound, tranchesWithTimestamps, protocolFee, brokerFee); + for (uint256 i = 0; i < tranchesWithTimestamps.length; ++i) { + tranches[i].amount = tranchesWithTimestamps[i].amount; + } + } + + /// @dev Fuzzes the tranche amounts and calculates the create amounts (total, deposit, protocol fee and broker + /// fee). + function fuzzTranchedStreamAmounts( + uint128 upperBound, + LockupTranched.Tranche[] memory tranches, + UD60x18 protocolFee, + UD60x18 brokerFee + ) + internal + pure + returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) + { + uint256 trancheCount = tranches.length; + uint128 maxTrancheAmount = upperBound / uint128(trancheCount * 2); + + // Precompute the first tranche amount to prevent zero deposit amounts. + tranches[0].amount = boundUint128(tranches[0].amount, 100, maxTrancheAmount); + uint128 estimatedDepositAmount = tranches[0].amount; + + // Fuzz the other tranche amounts by bounding from 0. + unchecked { + for (uint256 i = 1; i < trancheCount; ++i) { + tranches[i].amount = boundUint128(tranches[i].amount, 0, maxTrancheAmount); + estimatedDepositAmount += tranches[i].amount; + } + } + + // Calculate the total amount from the approximated deposit amount (recall that the sum of all tranche amounts + // must equal the deposit amount) using this formula: + // + // $$ + // total = \frac{deposit}{1e18 - protocolFee - brokerFee} + // $$ + totalAmount = ud(estimatedDepositAmount).div(ud(uUNIT - protocolFee.intoUint256() - brokerFee.intoUint256())) + .intoUint128(); + + // Calculate the fee amounts. + createAmounts.protocolFee = ud(totalAmount).mul(protocolFee).intoUint128(); + createAmounts.brokerFee = ud(totalAmount).mul(brokerFee).intoUint128(); + + // Here, we account for rounding errors and adjust the estimated deposit amount and the tranches. We know + // that the estimated deposit amount is not greater than the adjusted deposit amount below, because the inverse + // of {Helpers.checkAndCalculateFees} over-expresses the weight of the fees. + createAmounts.deposit = totalAmount - createAmounts.protocolFee - createAmounts.brokerFee; + tranches[tranches.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); + } + + /// @dev Fuzzes the durations. + function fuzzTrancheDurations(LockupTranched.TrancheWithDuration[] memory tranches) internal view { + unchecked { + // Precompute the first tranche duration. + tranches[0].duration = uint40(_bound(tranches[0].duration, 1, 100)); + + // Bound the durations so that none is zero and the calculations don't overflow. + uint256 durationCount = tranches.length; + uint40 maxDuration = (MAX_UNIX_TIMESTAMP - getBlockTimestamp()) / uint40(durationCount); + for (uint256 i = 1; i < durationCount; ++i) { + tranches[i].duration = boundUint40(tranches[i].duration, 1, maxDuration); + } + } + } + + /// @dev Fuzzes the tranche timestamps. + function fuzzTrancheTimestamps(LockupTranched.Tranche[] memory tranches, uint40 startTime) internal view { + // Return here if there's only one tranche to not run into division by zero. + uint40 trancheCount = uint40(tranches.length); + if (trancheCount == 1) { + // The end time must be in the future. + uint40 currentTime = getBlockTimestamp(); + tranches[0].timestamp = (startTime < currentTime ? currentTime : startTime) + 2 days; + return; + } + + // The first timestamps is precomputed to avoid an underflow in the first loop iteration. We have to + // add 1 because the first timestamp must be greater than the start time. + tranches[0].timestamp = startTime + 1 seconds; + + // Fuzz the timestamps while preserving their order in the array. For each timestamp, set its initial guess + // as the sum of the starting timestamp and the step size multiplied by the current index. This ensures that + // the initial guesses are evenly spaced. Next, we bound the timestamp within a range of half the step size + // around the initial guess. + uint256 start = tranches[0].timestamp; + uint40 step = (MAX_UNIX_TIMESTAMP - tranches[0].timestamp) / (trancheCount - 1); + uint40 halfStep = step / 2; + for (uint256 i = 1; i < trancheCount; ++i) { + uint256 timestamp = start + i * step; + timestamp = _bound(timestamp, timestamp - halfStep, timestamp + halfStep); + tranches[i].timestamp = uint40(timestamp); + } + } } diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index a5246bf4c..815c6d8f1 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -5,6 +5,7 @@ pragma solidity >=0.8.22; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2NFTDescriptor } from "../../src/SablierV2NFTDescriptor.sol"; @@ -18,7 +19,7 @@ contract Precompiles { CONSTANTS //////////////////////////////////////////////////////////////////////////*/ - uint256 internal constant MAX_SEGMENT_COUNT = 300; + uint256 internal constant MAX_COUNT = 500; /*////////////////////////////////////////////////////////////////////////// BYTECODES @@ -30,8 +31,10 @@ contract Precompiles { hex"60c0346200046e57601f62005f8a38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615af6908162000494823960805181613d2b015260a051818181610e350152613e4c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a714612a185750806306fdde031461291b578063081812fc146128fd578063095ea7b3146127f65780631400ecec146127505780631c1cdd4c146126ea5780631e99d569146126cc57806323b872dd146126b557806331df3d48146125b257806339a73c031461256f57806340e58ee514612277578063425d30dd1461222157806342842e0e146121d057806342966c6814611fbd5780634426757014611f965780634857501f14611f1c5780634869e12d14611edf5780634cc55e1114611de457806354c0229214611b485780635fe3b56714611b215780636352211e14611af25780636d0cee7514611af257806370a0823114611a7e57806375829def146119e45780637cad6cd1146118e65780637de6b1db146116c95780638659c27014611379578063894e9a0d14610ff35780638bad38dd14610f485780638f69b99314610ead5780639067b67714610e585780639188ec8414610e1d57806395d89b4114610d09578063a22cb46514610c4b578063a6202bf214610b43578063a80fc07114610aec578063ad35efd414610a73578063b256456914610a1d578063b637b865146109be578063b88d4fde14610935578063b8a3be66146108ff578063b971302a146108ab578063bc063e1a14610888578063bc2be1be14610833578063c156a11d146106dd578063c87b56dd146105c9578063cc364f481461052d578063d4dbd20b146104d6578063d511609f14610485578063d975dfed14610437578063e985e9c5146103e0578063ea5ead19146103b2578063eac8f5b81461035b578063f590c176146102f6578063f851a440146102cf5763fdd46d601461028957600080fd5b346102ca5760603660031901126102ca576102a2612b44565b604435906001600160801b03821682036102ca576102c8926102c2613d21565b3561371c565b005b600080fd5b346102ca5760003660031901126102ca5760206001600160a01b0360005416604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360016040600020015416604051908152f35b50346102ca5760403660031901126102ca576102c890356103d1612b44565b6103da8261467a565b9161337a565b346102ca5760403660031901126102ca576103f9612b2e565b610401612b44565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760206104748361467a565b6001600160801b0360405191168152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060026040600020015460801c604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360036040600020015416604051908152f35b50346102ca5760203660031901126102ca578035906000602060405161055281612c94565b828152015281600052600b60205260ff60016040600020015460a81c16156103465750600052600b6020526040806000205464ffffffffff82519161059683612c94565b818160a01c16835260c81c1660208201526105c7825180926020908164ffffffffff91828151168552015116910152565bf35b50346102ca576020806003193601126102ca57600082356105e981613aa2565b5060446001600160a01b03600a54169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106d157600092610658575b50610654604051928284938452830190612b09565b0390f35b9091503d806000833e61066b8183612ce1565b81019082818303126102ca5780519067ffffffffffffffff82116102ca570181601f820112156102ca5780516106a081612d03565b926106ae6040519485612ce1565b8184528482840101116102ca576106ca91848085019101612ae6565b903861063f565b6040513d6000823e3d90fd5b50346102ca5760403660031901126102ca578035906106fa612b44565b91610703613d21565b80600052600b60205260ff60016040600020015460a81c161561081d578060005260056020526001600160a01b038060406000205416938433036107fa5761074a8361467a565b6001600160801b0381166107e9575b50818116156107d1578261076c91613bdc565b9081168061078b576024848460405191637e27328960e01b8352820152fd5b840361079357005b6107cd916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107f490868561337a565b38610759565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102ca5760003660031901126102ca57602060405167016345785d8a00008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360406000205416604051908152f35b50346102ca5760203660031901126102ca5735600052600b602052602060ff60016040600020015460a81c166040519015158152f35b50346102ca5760803660031901126102ca5761094f612b2e565b610957612b44565b906064359267ffffffffffffffff84116102ca57366023850112156102ca578301359161098383612d03565b926109916040519485612ce1565b80845236602482870101116102ca5760208160009260246102c89801838801378501015260443591613206565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600c602052610654610a096040600020613176565b604051918291602083526020830190612bd4565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460b01c166040519015158152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610aad90613b55565b604051906005811015610ac257602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360026040600020015416604051908152f35b50346102ca5760203660031901126102ca57610b5d612b2e565b906001600160a01b038060005416338103610c1c57508216918260005260026020526001600160801b0360406000205416918215610bec575081610bbe9184600052600260205260406000206001600160801b0319815416905533906145ee565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b60249084604051917f8410168c000000000000000000000000000000000000000000000000000000008352820152fd5b604080516331b339a960e21b81526001600160a01b039092169382019384523360208501529092839250010390fd5b50346102ca5760403660031901126102ca57610c65612b2e565b602435908115158092036102ca576001600160a01b0316918215610cd95750336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760003660031901126102ca576040519060009080549160018360011c9260018516948515610e13575b6020958686108114610dfe57858852879493929187908215610ddc575050600114610d80575b5050610d6c92500383612ce1565b610654604051928284938452830190612b09565b8592506000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610dc4575050610d6c93508201013880610d5e565b80548389018501528794508693909201918101610dac565b9250935050610d6c94915060ff191682840152151560051b8201013880610d5e565b602283634e487b7160e01b6000525260246000fd5b93607f1693610d38565b346102ca5760003660031901126102ca5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610ee790613b55565b9060058210159081610f255760028314918215610f3a575b8215610f13575b6020836040519015158152f35b909150610f2557602091143880610f06565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610eff565b50346102ca5760203660031901126102ca5780356001600160a01b03918282168092036102ca578260005416338103610fc557505060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b604080516331b339a960e21b81526001600160a01b0390921692820192835233602084015290918291010390fd5b50346102ca5760203660031901126102ca57604051610160810181811067ffffffffffffffff821117611364576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e0820152600061010082015261106e613123565b61012082015201528035600052600b60205260ff60016040600020015460a81c161561134c578035600052600b60205260406000209061113e6002604051936110b685612cc4565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613142565b61012083015261114e8135613b55565b60058110156113375760021461132b575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600c602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761131657506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161123990613176565b82820152610654604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130261012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190612bd4565b604190634e487b7160e01b6000525260246000fd5b6000606083015261115f565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b50346102ca57602090816003193601126102ca57803567ffffffffffffffff81116102ca576113ab9036908301612ba3565b90926113b5613d21565b6000915b8083106113c257005b6113cd8382876130c8565b35926113d7613d21565b83600052600b9081845260ff9160019280846040600020015460a81c16156116b357866000528186526040600020818582015460a01c1660001461142c576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c61169c5761145c81600052600b6020526001600160a01b0360406000205416331490565b1561167a5761146a81613add565b92816000528088526114826002604060002001613142565b936001600160801b03938486511685831610156116635783600052828a5260406000205460f01c161561164c5780848a6114c26114cc94838a5116612d57565b9701511690612d57565b9382600052818952886040600020977f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50895497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a16178b5560038882169b8c15611633575b0197851697886001600160801b03198254161790556001600160a01b038099169889936005865281604060002054169788965260406000200154169461157c8985886145ee565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6115df575b50505050600191500191906113b9565b803b156102ca578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611624575b8080806115cf565b61162d90612cb0565b3861161c565b848101600160a01b60ff60a01b19825416179055611535565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b50346102ca57602090816003193601126102ca5780356116e7613d21565b80600052600b835260ff60016040600020015460a81c161561081d5761170c81613b55565b926005841015610ac257838303611734576024838360405191634a5541ef60e01b8352820152fd5b6003840361175357602483836040519163fe19f19f60e01b8352820152fd5b90600284146118cf5761177c81600052600b6020526001600160a01b0360406000205416331490565b156118ad5780600052600b825260ff60406000205460f01c16156118965780600052600b8252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600583526001600160a01b036040600020541693843b611822575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b156102ca578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611887575b806117f6565b61189090612cb0565b83611881565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b50346102ca5760203660031901126102ca5780356001600160a01b03908181168091036102ca5781600054163381036119b85750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101919082116119a3577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576119fe612b2e565b600054906001600160a01b0390818316338103611a5257506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576001600160a01b03611aa0612b2e565b16908115611ac1575060005260066020526020604060002054604051908152f35b6024906000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760203660031901126102ca57611b1060209135613aa2565b6001600160a01b0360405191168152f35b346102ca5760003660031901126102ca5760206001600160a01b0360015416604051908152f35b50346102ca576020906003199082823601126102ca5780359167ffffffffffffffff908184116102ca57610120843603918201126102ca57611b88613d21565b60c484013590602219018112156102ca57830182810135908282116102ca5760240160608202360381136102ca57611bc1913691612ff9565b9283519281611bcf85612fe1565b94611bdd6040519687612ce1565b808652601f19611bec82612fe1565b018860005b828110611dc65750505064ffffffffff90814216956001600160801b039889611c1982613d7d565b515116828c611c2784613d7d565b5101511685806040611c3886613d7d565b510151168b01169060405192611c4d84612c78565b83528d8301526040820152611c618a613d7d565b52611c6b89613d7d565b5060019360015b8c8b8d878410611d3757908c8a611c8a818e01613102565b92611c9760248301613102565b92611ca4604484016130ee565b946064840135946001600160a01b03958681168091036102ca57611d2f98611cef98611d2498611cd660848a01613116565b9481611ce460a48c01613116565b976040519d8e612c45565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613099565b610100820152613d9e565b604051908152f35b8899509084806040611d748a87611d648c9d9e9f9b9c99988b90611d5b828d613d8a565b5151169a613d8a565b5101511694600019890190613d8a565b51015116816040611d85888c613d8a565b5101511601169160405193611d9985612c78565b84528301526040820152611dad828d613d8a565b52611db8818c613d8a565b500190879594939291611c72565b9091929350611dd3613123565b82828a010152019088859392611bf1565b50346102ca5760403660031901126102ca5767ffffffffffffffff9080358281116102ca57611e169036908301612ba3565b926024359081116102ca57611e2e9036908401612ba3565b919092611e39613d21565b828503611ea9575060005b848110611e4d57005b80611ea3611e5e60019388866130c8565b35611e6a8389876130c8565b3560005260056020526001600160a01b0360406000205416611e95611e9085898b6130c8565b6130ee565b91611e9e613d21565b61371c565b01611e44565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657602061047483614b1c565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657600090611f5a83613b55565b906005821015610f255750600203611f7a575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611f6d565b346102ca5760003660031901126102ca5760206001600160a01b03600a5416604051908152f35b50346102ca57602090816003193601126102ca57803591611fdc613d21565b82600052600b815260ff60016040600020015460a81c16156121ba5782600052600b815260ff60016040600020015460a01c161561218a5761201d83614585565b156121665782600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c1615908161215c575b5080612154575b61213d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526005835260406000205416918215928315612102575b856000526005825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a16120ec57005b60249160405191637e27328960e01b8352820152fd5b61212386600052600760205260406000206001600160a01b03198154169055565b80600052600682526040600020600019815401905561209c565b6024838560405191630da9b01360e01b8352820152fd5b50600061205c565b9050151538612055565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b50346102ca576121df36612b6e565b90604051926020840184811067ffffffffffffffff82111761220c576102c8955060405260008452613206565b604186634e487b7160e01b6000525260246000fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460a01c166040519015158152f35b50346102ca57602090816003193601126102ca578035612295613d21565b80600052600b80845260ff60016040600020015460a81c16156125595781600052808452604060002060ff600182015460a01c166000146122e7576024848460405191634a5541ef60e01b8352820152fd5b5460f81c6125425761230f82600052600b6020526001600160a01b0360406000205416331490565b156125205761231d82613add565b92826000528185526123356002604060002001613142565b936001600160801b0390818651168282161015612509578460005283875260ff60406000205460f01c16156124f257866123c482847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a6123ba7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612d57565b9a01511690612d57565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156124d8575b0195811695866001600160801b03198254161790556001600160a01b03809a169a8b91600586528a6124828d604060002054169d8e96895260016040600020015416966124588b878a6145ee565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61249457005b843b156102ca576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16124cf57005b6102c890612cb0565b60018101600160a01b60ff60a01b1982541617905561240a565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b346102ca5760203660031901126102ca576001600160a01b03612590612b2e565b16600052600260205260206001600160801b0360406000205416604051908152f35b50346102ca57600319906020368301126102ca5780359167ffffffffffffffff908184116102ca576101409084360301126102ca576125ef613d21565b604051906125fc82612c45565b612607848401612b5a565b825261261560248501612b5a565b602083015261262660448501612d1f565b604083015261263760648501612b5a565b606083015261264860848501612c38565b608083015261265960a48501612c38565b60a083015261266a60c48501612fcf565b60c083015260e48401359081116102ca57830191366023840112156102ca576020936126a5611d2492611d2f95602436928201359101612ff9565b60e0840152610104369101613099565b346102ca576102c86126c636612b6e565b91612d86565b346102ca5760003660031901126102ca576020600954604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad75761272490613b55565b906005821015610f255760208215838115612745575b506040519015158152f35b60019150148261273a565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760208260009080600052600b8352604060002060ff815460f01c16806127e4575b6127bb575b50506001600160801b0360405191168152f35b6127dd92506001600160801b0360026127d79201541691613add565b90612d57565b82806127a8565b5060ff600182015460a01c16156127a3565b50346102ca5760403660031901126102ca57612810612b2e565b906024359061281e82613aa2565b90331515806128ea575b806128bc575b61288b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260076020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600860205260406000203360005260205260ff604060002054161561282e565b50336001600160a01b0383161415612828565b50346102ca5760203660031901126102ca57611b1060209135612d33565b50346102ca5760003660031901126102ca576040519060006003549060018260011c92600181168015612a0e575b60209586861082146129f9575084875286939291869082156129d957505060011461297c575b50610d6c92500383612ce1565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106129c1575050610d6c93508201013861296f565b805483890185015287945086939092019181016129aa565b60ff191685820152610d6c95151560051b850101925038915061296f9050565b602290634e487b7160e01b6000525260246000fd5b93607f1693612949565b82346102ca5760203660031901126102ca5735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102ca57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612abc575b8115612a92575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612a8b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612a84565b60005b838110612af95750506000910152565b8181015183820152602001612ae9565b90602091612b2281518092818552858086019101612ae6565b601f01601f1916010190565b600435906001600160a01b03821682036102ca57565b602435906001600160a01b03821682036102ca57565b35906001600160a01b03821682036102ca57565b60609060031901126102ca576001600160a01b039060043582811681036102ca579160243590811681036102ca579060443590565b9181601f840112156102ca5782359167ffffffffffffffff83116102ca576020808501948460051b0101116102ca57565b90815180825260208080930193019160005b828110612bf4575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612be6565b359081151582036102ca57565b610120810190811067ffffffffffffffff821117612c6257604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612c6257604052565b6040810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257604052565b610140810190811067ffffffffffffffff821117612c6257604052565b90601f8019910116810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257601f01601f191660200190565b35906001600160801b03821682036102ca57565b612d3c81613aa2565b5060005260076020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612d7057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612fb75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c16159081612fad575b5080612fa5575b612f8e578685526005815282848620541694873315159384612ede575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612ea6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612e785750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612ec782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055612e14565b91929380915090612f4d575b15612ef85790878392612deb565b848887612f15576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612f72575b80612eea5750878252600783523384868420541614612eea565b5085825260088352848220338352835260ff8583205416612f58565b602487855190630da9b01360e01b82526004820152fd5b506001612dce565b9050151538612dc7565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff821682036102ca57565b67ffffffffffffffff8111612c625760051b60200190565b92919261300582612fe1565b6040946130156040519283612ce1565b819584835260208093019160608096028501948186116102ca57925b8584106130415750505050505050565b86848303126102ca5782519061305682612c78565b61305f85612d1f565b8252858501359067ffffffffffffffff821682036102ca57828792838b95015261308a868801612fcf565b86820152815201930192613031565b91908260409103126102ca576040516130b181612c94565b60208082946130bf81612b5a565b84520135910152565b91908110156130d85760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102ca5790565b356001600160a01b03811681036102ca5790565b3580151581036102ca5790565b6040519061313082612c78565b60006040838281528260208201520152565b9060405161314f81612c78565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b90815461318281612fe1565b926040936131936040519182612ce1565b82815280946020809201926000526020600020906000935b8585106131ba57505050505050565b600184819284516131ca81612c78565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c16868201528152019301940193916131ab565b9190613213828285612d86565b803b613220575b50505050565b61327c6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612b09565b03906020816000938185885af190829082613312575b50506132c957826132a161464a565b80519190826132c25760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036132fa57503880808061321a565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613372575b8161332f60209383612ce1565b8101031261336e5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361336b5750903880613292565b80fd5b5080fd5b3d9150613322565b92919092613386613d21565b600093818552600b9260209380855260409260ff6001858a20015460a81c16156137065784885281865260ff6001858a20015460a01c166136ef576001600160a01b03918282169283156136df576001600160801b03938486169182156136c857888c5260058a5280888d2054169384831415806136b8575b6136955761340c8a61467a565b878116851161366457508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061343d916146a2565b878752838652828720600201908282549160801b6001600160801b031916911617815561346990613142565b90808683015116918184818351169201511661348491612d57565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d96613637575b878252855220015416946134c78189886145ee565b8a51908152a4803314158061362d575b6135c8575b8233141590816135bd575b816135b2575b50613521575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156135ae578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af161359f575b8594816134f3565b6135a890612cb0565b38613597565b8780fd5b9050821415386134ed565b833b151591506134e7565b803b15613629578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af161361a575b506134dc565b61362390612cb0565b38613614565b8880fd5b50803b15156134d7565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134b2565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506136c28a614585565b156133ff565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b92919092600093818552600b9060209382855260409260ff6001858a20015460a81c1615613706578785815281875260ff6001868320015460a01c16613a8b576001600160a01b0390818516928315613a7b576001600160801b0393848616918215613a645789845260058b52848985205416948583141580613a54575b613a31576137c18b838e6137ad83614b1c565b9289525260028c8820015460801c90612d57565b8781168511613a005750908b8b928387528282528b808820998b838c54169b6002015460801c906137f1916146a2565b868a52858552828a20600201908282549160801b6001600160801b031916911617815561381d90613142565b8180868301511693818351169201511661383691612d57565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936139d2575b848852825260018c88200154169461387a818c886145ee565b8b51908152a481331415806139c8575b613962575b50813314159081613957575b8161394c575b506138d4575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613948578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613930575b80806134f3565b61393a8691612cb0565b6139445784613929565b8480fd5b8280fd5b9050811415386138a1565b823b1515915061389b565b813b1561336b578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16139b4575b5061388f565b6139c091929a50612cb0565b9738806139ae565b50813b151561388a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613861565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b50613a5e8b614585565b1561379a565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260056020526001600160a01b0360406000205416908115613ac5575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c161015613b4b5760c81c161115613b395750600c602052600160406000205411600014613b3057613b2d9061478e565b90565b613b2d906146bd565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c16600014613b7c575050600490565b805460f81c613bd5575460a01c64ffffffffff164210613bcf57613b9f81613add565b90600052600b6020526001600160801b038060026040600020015416911610600014613bca57600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613d17575b5080613d0c575b613cf5579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613cbd575b169283613ca7575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613c83565b613cde86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613c7b565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c1a565b9050151538613c13565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613d5357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b8051156130d85760200190565b80518210156130d85760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106d157600090614551575b613e2091506001600160801b0360408501511690602061010086015101519161496e565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452757815180156144fd577f000000000000000000000000000000000000000000000000000000000000000081116144cc575064ffffffffff6040613e8384613d7d565b510151168110156144755750600090819082815184905b8082106143e4575050505064ffffffffff421664ffffffffff82168110156143a45750506001600160801b031680820361436d5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000604061402d8951996000198b0190613d8a565b51015160c81b169560f01b16911617171717845560005b81811061429b575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b036020830151168015612fb7576140cf866001600160a01b0392613bdc565b1661426a576141046001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614aad565b6001600160801b036040820151168061423a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6141f76001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661422f61420f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a38c612c94565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190612bd4565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b614264906001600160a01b036060850151166001600160a01b036101008601515116903390614aad565b38614118565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906142b88160e0870151613d8a565b51825468010000000000000000811015612c6257600181018085558110156130d857600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501614044565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614408906001600160801b036143ff8588613d8a565b515116906146a2565b9364ffffffffff80604061441c8685613d8a565b5101511694168085111561443857506001849301909291613e9a565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061448684613d7d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161457d575b8161456b60209383612ce1565b810103126102ca57613e209051613dfc565b3d915061455e565b60009080825260056020526001600160a01b0380604084205416928333149384156145ca575b505082156145b857505090565b9091506145c53392612d33565b161490565b60ff92945090604091815260086020528181203382526020522054169138806145ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261464891614643606483612ce1565b614b97565b565b3d15614675573d9061465b82612d03565b916146696040519384612ce1565b82523d6000602084013e565b606090565b613b2d9061468781614b1c565b90600052600b60205260026040600020015460801c90612d57565b9190916001600160801b0380809416911601918211612d7057565b64ffffffffff6146f2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614c33565b91808252600c6020526040822080541561477a5790829167ffffffffffffffff935261474c6020832054828452600b6020526147476001600160801b03968760026040882001541696879360801c1690614d23565b614d91565b92831361476257505061475e90614e7b565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff8042166000838152600b602052604091828220908351916147b483612cc4565b80549661012061483a60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201613142565b94019384528452600c602052614851858520613176565b918496808761485f86613d7d565b5101511692828288955b16106149385750916148ed614747928488816148f298976001600160801b039e8f614894898c613d8a565b5151169d8e9a67ffffffffffffffff60206148af8c84613d8a565b510151169984836148c08385613d8a565b510151169650801561492c576148dc9293506000190190613d8a565b5101511680925b0316920316614c33565b614d23565b92831361490b5750506149058391614e7b565b16011690565b5160200151929392831692841683101591506149279050575090565b905090565b505050511680926148e3565b8093986001600160801b03908161494f8c89613d8a565b51511601169801928282808a614965888a613d8a565b51015116614869565b909291614979613123565b936001600160801b0392838116918215614a855767016345785d8a0000808211614a4e57808511614a1757506149c3856149b48193866159a7565b169460208901958652846159a7565b1691846149da6040890194808652828751166146a2565b161015614a01576149f38491826149fc95511690612d57565b91511690612d57565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614a9881612c78565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612c625761464892604052614b97565b80600052600b602052614b356002604060002001613142565b81600052600b602052604060002060ff600182015460a01c16600014614b6857506001600160801b039150602001511690565b5460f81c614b7a5750613b2d90613add565b613b2d91506001600160801b036040818351169201511690612d57565b6001600160a01b031690614bc2600080836020829551910182875af1614bbb61464a565b9084615a56565b908151918215159283614c0b575b505050614bda5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261336e57602001519081159182150361336b5750388080614bd0565b600160ff1b808214908115614d19575b50614cef576000811215614ce657614c6c816000035b6000841215614cdf578360000390614eb7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614ca85760001991181315614ca25790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614eb7565b614c6c81614c59565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c43565b80614d3e5750614d3957670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614d8b575080614d63575050670de0b6b3a764000090565b670de0b6b3a76400008114614d8757614d8290614747613b2d93614fb1565b6150f3565b5090565b91505090565b600160ff1b808214908115614e71575b50614e47576000811215614e3e57614dca816000035b6000841215614e375783600003906159a7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614e005760001991181315614ca25790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906159a7565b614dca81614db7565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614da1565b60008112614e865790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614f735782851015614f3757908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614f81570490565b634e487b7160e01b600052601260045260246000fd5b8015614f81576ec097ce7bc90715b34b9f10000000000590565b806000808313156150c257670de0b6b3a76400009283811261509f57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d9082821461509357506706f05b59d3b20000905b8482136150675750505050500290565b808391020590671bc16d674ec80000821215615086575b831d90615057565b8091950194831d9061507e565b93505093925050020290565b6000199392508015614f81576ec097ce7bc90715b34b9f10000000000591614fd2565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60008112156151225768033dd1780914b97114198112613bcf57615119906000036150f3565b613b2d90614f97565b680a688906bd8affffff811361597657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615859575b66ff0000000000008316615751575b65ff00000000008316615651575b64ff000000008316615559575b63ff0000008316615469575b62ff00008316615381575b61ff0083166152a1575b60ff83166151ca575b02911c60bf031c90565b6080831661528f575b83831661527d575b6020831661526b575b60108316615259575b60088316615247575b60048316615235575b60028316615223575b60018316156151c0576801000000000000000102831c6151c0565b6801000000000000000102831c615208565b6801000000000000000302831c6151ff565b6801000000000000000602831c6151f6565b6801000000000000000b02831c6151ed565b6801000000000000001602831c6151e4565b6801000000000000002c02831c6151db565b6801000000000000005902831c6151d3565b618000831661536f575b614000831661535d575b612000831661534b575b6110008316615339575b6108008316615327575b6104008316615315575b6102008316615303575b6101008316156151b757680100000000000000b102831c6151b7565b6801000000000000016302831c6152e7565b680100000000000002c602831c6152dd565b6801000000000000058c02831c6152d3565b68010000000000000b1702831c6152c9565b6801000000000000162e02831c6152bf565b68010000000000002c5d02831c6152b5565b680100000000000058b902831c6152ab565b628000008316615457575b624000008316615445575b622000008316615433575b621000008316615421575b62080000831661540f575b6204000083166153fd575b6202000083166153eb575b620100008316156151ad576801000000000000b17202831c6151ad565b680100000000000162e402831c6153ce565b6801000000000002c5c802831c6153c3565b68010000000000058b9102831c6153b8565b680100000000000b172102831c6153ad565b68010000000000162e4302831c6153a2565b680100000000002c5c8602831c615397565b6801000000000058b90c02831c61538c565b63800000008316615547575b63400000008316615535575b63200000008316615523575b63100000008316615511575b630800000083166154ff575b630400000083166154ed575b630200000083166154db575b63010000008316156151a25768010000000000b1721802831c6151a2565b6801000000000162e43002831c6154bd565b68010000000002c5c86002831c6154b1565b680100000000058b90c002831c6154a5565b6801000000000b17217f02831c615499565b680100000000162e42ff02831c61548d565b6801000000002c5c85fe02831c615481565b68010000000058b90bfc02831c615475565b648000000000831661563f575b644000000000831661562d575b642000000000831661561b575b6410000000008316615609575b64080000000083166155f7575b64040000000083166155e5575b64020000000083166155d3575b64010000000083161561519657680100000000b17217f802831c615196565b68010000000162e42ff102831c6155b4565b680100000002c5c85fe302831c6155a7565b6801000000058b90bfce02831c61559a565b68010000000b17217fbb02831c61558d565b6801000000162e42fff002831c615580565b68010000002c5c8601cc02831c615573565b680100000058b90c0b4902831c615566565b65800000000000831661573f575b65400000000000831661572d575b65200000000000831661571b575b651000000000008316615709575b6508000000000083166156f7575b6504000000000083166156e5575b6502000000000083166156d3575b65010000000000831615615189576801000000b17218355102831c615189565b680100000162e430e5a202831c6156b3565b6801000002c5c863b73f02831c6156a5565b68010000058b90cf1e6e02831c615697565b680100000b1721bcfc9a02831c615689565b68010000162e43f4f83102831c61567b565b680100002c5c89d5ec6d02831c61566d565b6801000058b91b5bc9ae02831c61565f565b66800000000000008316615847575b66400000000000008316615835575b66200000000000008316615823575b66100000000000008316615811575b660800000000000083166157ff575b660400000000000083166157ed575b660200000000000083166157db575b660100000000000083161561517b5768010000b17255775c0402831c61517b565b6801000162e525ee054702831c6157ba565b68010002c5cc37da949202831c6157ab565b680100058ba01fb9f96d02831c61579c565b6801000b175effdc76ba02831c61578d565b680100162f3904051fa102831c61577e565b6801002c605e2e8cec5002831c61576f565b68010058c86da1c09ea202831c615760565b6780000000000000008316615957575b6740000000000000008316615945575b6720000000000000008316615933575b6710000000000000008316615921575b670800000000000000831661590f575b67040000000000000083166158fd575b67020000000000000083166158eb575b67010000000000000083161561516c57680100b1afa5abcbed6102831c61516c565b68010163da9fb33356d802831c6158c9565b680102c9a3e778060ee702831c6158b9565b6801059b0d31585743ae02831c6158a9565b68010b5586cf9890f62a02831c615899565b6801172b83c7d517adce02831c615889565b6801306fe0a31b7152df02831c615879565b5077b504f333f9de648480000000000000000000000000000000615869565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b90919060001983820983820291828083109203918083039214615a4557670de0b6b3a76400009081831015615a0e57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90615a955750805115615a6b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615ae0575b615aa6575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15615a9e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = hex"60a034620003e757601f196001600160401b03601f62004cd43881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516148b1908162000423823960805181613aba0152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146130d15750806306fdde031461300d578063081812fc14612fee578063095ea7b314612ef55780631400ecec14612e555780631c1cdd4c14612df05780631e99d56914612dd257806323b872dd14612dba57806339a73c0314612d7957806340e58ee514612b05578063425d30dd14612ab457806342842e0e14612a6457806342966c681461288957806344267570146128625780634857501f146127ec5780634869e12d146127b15780634cc55e111461233357806353b15727146122145780635fe3b567146121ed5780636352211e146121bd5780636d0cee75146121bd57806370a082311461214d57806375829def146120ba578063780a82c81461206d5780637cad6cd114611f9c5780637de6b1db14611d755780638659c27014611a26578063894e9a0d146117375780638bad38dd146116ba5780638f69b9931461161e5780639067b677146115ce57806395d89b41146114bf578063a22cb46514611402578063a6202bf214611305578063a80fc071146112b3578063ab167ccc14611164578063ad35efd414611102578063b2564569146110b1578063b88d4fde14611024578063b8a3be6614610fef578063b971302a14610fa0578063bc063e1a14610f7d578063bc2be1be14610f2d578063c156a11d14610a91578063c87b56dd14610975578063cc364f48146108aa578063d4dbd20b14610858578063d511609f1461080c578063d975dfed146107c0578063e985e9c51461076b578063ea5ead1914610743578063eac8f5b8146106f1578063f590c1761461068f578063f851a440146106695763fdd46d601461027e57600080fd5b34610666576060366003190112610666576004359061029b613200565b916102a461335d565b926102ad613ab0565b818352600b9360209185835260ff600160408720015460a81c161561064f5783855285835260ff600160408720015460a01c16610637576001600160a01b039182821692831561060d576001600160801b03938483169081156105f557878952600587528260408a2054169283821415806105e5575b6105c1576103308961437b565b878116841161058f575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610364916143a6565b858d5284845260408d20600201906103979082906001600160801b036001600160801b031983549260801b169116179055565b6103a090613654565b908084830151169181808251169160400151166103bc91613397565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610560575b848c528252600160408c2001541694610401818a886142ef565b604051908152a48033141580610556575b6104e8575b8333141590816104dd575b816104d2575b5061045c575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104b6575b808061042e565b6104bf9061327c565b6104ca5782386104af565b8280fd5b8380fd5b905083141538610428565b843b15159150610422565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161053e575b5050610417565b6105479061327c565b610552578438610537565b8480fd5b50803b1515610412565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103e7565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105ef89613b0c565b15610323565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b50346106665780600319360112610666576001600160a01b036020915416604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da578160409160209352600b8352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760016040836001600160a01b039360209552600b855220015416604051908152f35b50346106665760403660031901126106665760043590610761613200565b916102a48161437b565b5034610666576040366003190112610666576107856131ea565b604061078f613200565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb60209161437b565b6001600160801b0360405191168152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408260029260209452600b845220015460801c604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760036040836001600160801b039360209552600b855220015416604051908152f35b5034610666576020908160031936011261066657600435916108ca613635565b50828252600b815260ff600160408420015460a81c161561095e576060928252600b815264ffffffffff9182604082205460a01c1692600c8352604081818420541692600b8552205460c81c169160405193610925856132ad565b8452830152604082015261095c60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043561099481613809565b50826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a85578093610a04575b5050610a006040519282849384528301906131c5565b0390f35b909192503d8082843e610a17818461331f565b8201918381840312610a815780519067ffffffffffffffff82116104ca570182601f82011215610a8157805191610a4d83613341565b93610a5b604051958661331f565b838552858484010111610666575090610a79918480850191016131a2565b9038806109ea565b5080fd5b604051903d90823e3d90fd5b503461066657604036600319011261066657600435610aae613200565b610ab6613ab0565b818352600b9060209082825260ff600160408720015460a81c161561064f57838552600582526001600160a01b03918260408720541693843303610f0e57610afd8661437b565b906001600160801b039081831680158015610b9d575b50505050505081811615610b855783610b2b9161396b565b90811680610b4b5760248460405190637e27328960e01b82526004820152fd5b8203610b55578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610ba5613ab0565b898b5282865260ff600160408d20015460a81c1615610ef757898b5282865260ff600160408d20015460a01c16610edf57881561060d57610ec757888a52600585528660408b205416918289141580610eb7575b610e9357610c068a61437b565b8481168311610e615750908a949392918a86528087526040862093610c70610c398760028d89541698015460801c6143a6565b8d8952838a52610c6b600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b613654565b90610c8c818a8401511692826040818351169201511690613397565b161115610e32575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cd38186886142ef565b604051908152a48033141580610e28575b610dbe575b813314159081610db3575b81610da8575b50610d37575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b13565b803b156104ca57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d90575b80610d00565b610d999061327c565b610da4578538610d8a565b8580fd5b905081141538610cfa565b823b15159150610cf4565b803b156104ce57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e14575b5050610ce9565b610e1d9061327c565b6104ce578338610e0d565b50803b1515610ce4565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c94565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ec18a613b0c565b15610bf9565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610666578060031936011261066657602060405167016345785d8a00008152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da576040826001600160a01b039260209452600b8452205416604051908152f35b50346106665760203660031901126106665760ff600160406020936004358152600b855220015460a81c166040519015158152f35b50346106665760803660031901126106665761103e6131ea565b611046613200565b906064359067ffffffffffffffff82116104ce57366023830112156104ce578160040135928461107585613341565b93611083604051958661331f565b8585523660248783010111610a8157856110ae9660246020930183880137850101526044359161369c565b80f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460b01c166040519015158152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5761113b906138e4565b60405190600581101561115057602092508152f35b602483634e487b7160e01b81526021600452fd5b5034610666576101403660031901126106665761117f613ab0565b611187613635565b9064ffffffffff8042168084528161119d613688565b16156112ac5781806111ad613688565b8301165b16602085015260e4359082821682036112a75701166040830152600435916001600160a01b03918284168094036112a757602435908382168092036112a757604435906001600160801b0382168092036112a757606435908582168092036106665750608435918215158093036112a75760a435938415158095036112a7576040519761123d89613290565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126112a7576040519161127783613303565b6101043591821682036112a7578261129f9260209452610124358482015260e0820152613b75565b604051908152f35b600080fd5b81836111b1565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760026040836001600160801b039360209552600b855220015416604051908152f35b50346106665760203660031901126106665761131f6131ea565b6001600160a01b03808354163381036113d9575081169081835260026020526001600160801b036040842054169081156113a85781611379918486526002602052604086206001600160801b0319815416905533906142ef565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106665760403660031901126106665761141c6131ea565b602435908115158092036112a7576001600160a01b031690811561148e5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657806003193601126106665760405190806004549160018360011c92600185169485156115c4575b60209586861081146115b05785885287949392918790821561158e575050600114611534575b50506115209250038361331f565b610a006040519282849384528301906131c5565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b85831061157657505061152093508201013880611512565b8054838901850152879450869390920191810161155e565b925093505061152094915060ff191682840152151560051b8201013880611512565b602483634e487b7160e01b81526022600452fd5b93607f16936114ec565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57611657906138e4565b906005821015908161169857600283149182156116ac575b8215611683575b6020836040519015158152f35b90915061169857506004602091143880611676565b80634e487b7160e01b602492526021600452fd5b50600383149150600061166f565b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d9575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b50346106665760203660031901126106665780610140604051611759816132c9565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152611795613635565b61012082015201526004358152600b60205260ff600160408320015460a81c1615611a0e576004358152600b60205260408120906118636002604051936117db856132e6565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613654565b6101208301526118746004356138e4565b60058110156119fa576101406101a093600264ffffffffff93146119ef575b6101208101518360406001600160a01b0360a085015116966004358152600c6020522054169084604084015116606084015115159661010085015115159160c086015115159060e08701511515926001600160a01b038851169a60808b60208b015116990151151590604051996119098b6132c9565b8d8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152610100840152610120830152828201526040519384528260208201511660208501526040810151151560408501526060810151151560608501526001600160a01b0360808201511660808501528260a08201511660a085015260c0810151151560c085015260e0810151151560e085015261010081015115156101008501526119e4610120820151610120860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b015116610180820152f35b836060820152611893565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461066657602080600319360112610a815760043567ffffffffffffffff81116104ca57611a5990369060040161324b565b9190611a63613ab0565b83925b808410611a71578480f35b611a7c84828461360f565b3593611a86613ab0565b848652600b80855260ff90600190828260408b20015460a81c1615611d5e57878952808752604089208281015460a01c841615611ad55760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d4657611b0681600052600b6020526001600160a01b0360406000205416331490565b15611d2657611b148161382c565b818a52828952611b29600260408c2001613654565b906001600160801b0395868351168783161015611d0e57838c52848b5260408c205460f01c1615611cf65791818a8c7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b9d878b85611b9360409b879f9e9d9b84905116613397565b9701511690613397565b85835286845287832098895490600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316178b5560038c84169b8c15611cdd575b019b87169b8c6001600160801b03198254161790556001600160a01b03808093169a8b96600589522054169889965260408d2001541694611c228b85886142ef565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611c86575b505050505050600101929190611a66565b813b15610da457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611cc9575b80808080611c75565b611cd29061327c565b610552578438611cc0565b828101600160a01b60ff60a01b19825416179055611be0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043590611d94613ab0565b818352600b815260ff600160408520015460a81c1615611f8557611db7826138e4565b6005811015611f715760048103611de05760248360405190634a5541ef60e01b82526004820152fd5b60038103611e00576024836040519063fe19f19f60e01b82526004820152fd5b600214611f5957611e2782600052600b6020526001600160a01b0360406000205416331490565b15611f3a57818352600b815260ff604084205460f01c1615611f2257818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b611eca575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104ca57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611f0e575b80611e9b565b611f179061327c565b6104ca578238611f08565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d95750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116120595760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600c8452205416604051908152f35b5034610666576020366003190112610666576120d46131ea565b9080546001600160a01b0380821693338503612126576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610666576020366003190112610666576001600160a01b0361216f6131ea565b16801561218c578160409160209352600683522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106665760203660031901126106665760206121dc600435613809565b6001600160a01b0360405191168152f35b503461066657806003193601126106665760206001600160a01b0360015416604051908152f35b5034610666576101603660031901126106665761222f613ab0565b6040519061223c82613290565b6122446131ea565b825261224e613200565b602083015261225b61335d565b60408301526001600160a01b039060643582811681036112a757606084015260843580151581036112a757608084015260a43580151581036112a75760a084015260603660c319011261066657506040516122b5816132ad565b64ffffffffff60c43581811681036112a757825260e43581811681036112a75760208301526101043590811681036112a757604082015260c08301526040610123193601126112a7576040519161230b83613303565b6101243591821682036112a7578261129f9260209452610144358482015260e0820152613b75565b50346106665760403660031901126106665767ffffffffffffffff6004358181116104ca5761236690369060040161324b565b90916024359081116104ce5761238090369060040161324b565b612388613ab0565b80830361277a57845b83811061239c578580f35b6123a781858761360f565b35906123b481868861360f565b35875260056020526001600160a01b036040882054166123d582858761360f565b35906001600160801b03821682036112a7576123ef613ab0565b838952600b60205260ff600160408b20015460a81c161561064f57838952600b60205260ff600160408b20015460a01c1661063757801561060d576001600160801b038216156127625783895260056020526001600160a01b0360408a205416918282141580612752575b61272e576124678561437b565b6001600160801b0381166001600160801b038316116126fe575090899291858452600b60205260408420926124e66001600160a01b0385541694610c6b6124b68560028094015460801c6143a6565b918a8952600b60205260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361250a8160208401511692826040818351169201511690613397565b1611156126cd575b868552600b6020526001600160a01b0360016040872001541661253f6001600160801b03841685836142ef565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126c3575b612659575b83331415908161264e575b81612643575b506125d1575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612391565b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161262b575b808061259a565b6126349061327c565b61263f578638612624565b8680fd5b905083141538612594565b843b1515915061258e565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af16126af575b5050612583565b6126b89061327c565b6105525784386126a8565b50803b151561257e565b868552600b6020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612512565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061275c85613b0c565b1561245a565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb6020916143c1565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f855780612827836138e4565b9260058410156119fa57600260209403612848575b50506040519015158152f35b8152600b8352604090205460f01c60ff169050388061283c565b503461066657806003193601126106665760206001600160a01b03600a5416604051908152f35b503461066657602080600319360112610a8157600435906128a8613ab0565b818352600b815260ff600160408520015460a81c1615611f8557818352600b815260ff600160408520015460a01c1615612a33576128e582613b0c565b15611f3a5781600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c16159081612a29575b5080612a21575b612a09577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260058352604060002054169182159283156129ce575b846000526005825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129b6575080f35b60249060405190637e27328960e01b82526004820152fd5b6129ef85600052600760205260406000206001600160a01b03198154169055565b806000526006825260406000206000198154019055612964565b60248360405190630da9b01360e01b82526004820152fd5b506000612924565b905015153861291d565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657612a7336613216565b60405191602083019383851067ffffffffffffffff861117612a9e576110ae9460405285845261369c565b634e487b7160e01b600052604160045260246000fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460a01c166040519015158152f35b503461066657602090816003193601126106665760043590612b25613ab0565b818152600b9283815260ff600160408420015460a81c161561095e5782825283815260408220600181015460a01c60ff1615612b735760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611d4657612b9e81600052600b6020526001600160a01b0360406000205416331490565b15611d2657612bac8161382c565b93818452808352612bc260026040862001613654565b916001600160801b0393848451168588161015611f595781865282815260ff604087205460f01c1615611f2257612c06878683611b938a9b838a9c9b9c5116613397565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d5f575b01988716988981546001600160801b0319161790556001600160a01b038096168097600585528760408b205416978893865260408b20600101541693612c928c84876142ef565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612d0e578480f35b823b15610552576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d50575b81818080808480f35b612d599061327c565b81612d47565b60018101600160a01b60ff60a01b19825416179055612c4b565b5034610666576020366003190112610666576001600160801b0360406020926001600160a01b03612da86131ea565b16815260028452205416604051908152f35b5034610666576110ae612dcc36613216565b916133c6565b50346106665780600319360112610666576020600954604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57612e29906138e4565b9060058210156116985760208215838115612e4a575b506040519015158152f35b600191501482612e3f565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f8557602091604082828152600b85522060ff815460f01c1680612ee3575b612eba575b50506001600160801b0360405191168152f35b612edc92506001600160801b036002612ed6920154169161382c565b90613397565b3880612ea7565b5060ff600182015460a01c1615612ea2565b503461066657604036600319011261066657612f0f6131ea565b602435612f1b81613809565b33151580612fdb575b80612fb1575b612f815781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600760205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260086020526040842033855260205260ff60408520541615612f2a565b50336001600160a01b0382161415612f24565b50346106665760203660031901126106665760206121dc600435613373565b503461066657806003193601126106665760405190806003549160018360011c92600185169485156130c7575b60209586861081146115b05785885287949392918790821561158e57505060011461306d5750506115209250038361331f565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8583106130af57505061152093508201013880611512565b80548389018501528794508693909201918101613097565b93607f169361303a565b905034610a81576020366003190112610a81576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104ca57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613178575b811561314e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613147565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613140565b60005b8381106131b55750506000910152565b81810151838201526020016131a5565b906020916131de815180928185528580860191016131a2565b601f01601f1916010190565b600435906001600160a01b03821682036112a757565b602435906001600160a01b03821682036112a757565b60609060031901126112a7576001600160a01b039060043582811681036112a7579160243590811681036112a7579060443590565b9181601f840112156112a75782359167ffffffffffffffff83116112a7576020808501948460051b0101116112a757565b67ffffffffffffffff8111612a9e57604052565b610100810190811067ffffffffffffffff821117612a9e57604052565b6060810190811067ffffffffffffffff821117612a9e57604052565b610160810190811067ffffffffffffffff821117612a9e57604052565b610140810190811067ffffffffffffffff821117612a9e57604052565b6040810190811067ffffffffffffffff821117612a9e57604052565b90601f8019910116810190811067ffffffffffffffff821117612a9e57604052565b67ffffffffffffffff8111612a9e57601f01601f191660200190565b604435906001600160801b03821682036112a757565b61337c81613809565b5060005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116133b057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156135f75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c161590816135ed575b50806135e5575b6135ce57868552600581528284862054169487331515938461351e575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876134e6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036134b85750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61350782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055613454565b9192938091509061358d575b15613538579087839261342b565b848887613555576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156135b2575b8061352a575087825260078352338486842054161461352a565b5085825260088352848220338352835260ff8583205416613598565b602487855190630da9b01360e01b82526004820152fd5b50600161340e565b9050151538613407565b6024604051633250574960e11b815260006004820152fd5b919081101561361f5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190613642826132ad565b60006040838281528260208201520152565b90604051613661816132ad565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112a75790565b91906136a98282856133c6565b803b6136b6575b50505050565b6137126001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906131c5565b03906020816000938185885af1908290826137a8575b505061375f578261373761434b565b80519190826137585760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036137905750388080806136b0565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613801575b816137c56020938361331f565b81010312610a815751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106665750903880613728565b3d91506137b8565b8060005260056020526001600160a01b03604060002054169081156129b6575090565b600090808252600c60205264ffffffffff918260408220541642106138de57600b6020526040812092835490808260c81c1691824210156138c85761387d9394955060a01c16809103904203614682565b90828152600b6020526001600160801b03926138a3846002604085200154168094614762565b9283116138b05750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b80600052600b602052604060002060ff600182015460a01c1660001461390b575050600490565b805460f81c613964575460a01c64ffffffffff16421061395e5761392e8161382c565b90600052600b6020526001600160801b03806002604060002001541691161060001461395957600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613aa6575b5080613a9b575b613a84579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613a4c575b169283613a36575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613a12565b613a6d86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613a0a565b602486885190630da9b01360e01b82526004820152fd5b5081811615156139a9565b90501515386139a2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ae257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b038060408420541692833314938415613b51575b50508215613b3f57505090565b909150613b4c3392613373565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613b32565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156142e3576000906142af575b613bf691506001600160801b0360408501511690602060e086015101519161443c565b916001600160801b0383511660c082015190156142855764ffffffffff8151161561425b5764ffffffffff81511690604081019164ffffffffff835116908181101561421b57505064ffffffffff60208201511680151580614209575b6141c75750602064ffffffffff9101511664ffffffffff825116908181101561418757505064ffffffffff8042169151169081811015614147575050600954926001600160801b0381511660405190613cab826132ad565b815260006020820152600060408201526001600160a01b0360608401511660c08401519064ffffffffff604083015116608086015115159060a087015115159064ffffffffff6001600160a01b038951169551169060405195613d0d876132e6565b8652602086019182526040860190815260608601938452608086016000815260a0870195865260c08701946000865260e08801936001855261010089019586526101208901998a528d600052600b6020527fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff00000000000000000000000000000000000000006001600160a01b0360406000209d5116945160a01b16965160c81b169351151560f01b169351151560f81b16931717171785556001600160a01b03600186019451167fffffffffffffffffff000000000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000075ff00000000000000000000000000000000000000000074ff000000000000000000000000000000000000000088549751151560a01b169451151560a81b169451151560b01b1694161717171790556001600160801b036040600360028401945193613ef484865116966001600160801b03199788825416178155856020880151166001600160801b036001600160801b031983549260801b169116179055565b01920151168282541617905564ffffffffff602060c085015101511680614129575b50600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b0360208301511680156135f757613f90856001600160a01b039261396b565b166140f857613fc56001600160a01b036060840151166001600160801b0380845116816020860151160116903090339061457b565b6001600160801b03604082015116806140c9575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140c06001600160a01b03606089015116976080810151151560a082015115159061408a6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b6140f2906001600160a01b036060850151166001600160a01b0360e0860151511690339061457b565b38613fd9565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600c60205260406000209064ffffffffff1982541617905538613f16565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b81516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508064ffffffffff8351161015613c53565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116142db575b816142c96020938361331f565b810103126112a757613bf69051613bd3565b3d91506142bc565b6040513d6000823e3d90fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526143499161434460648361331f565b6145e6565b565b3d15614376573d9061435c82613341565b9161436a604051938461331f565b82523d6000602084013e565b606090565b6143a390614388816143c1565b90600052600b60205260026040600020015460801c90613397565b90565b9190916001600160801b03808094169116019182116133b057565b80600052600b6020526143da6002604060002001613654565b81600052600b602052604060002060ff600182015460a01c1660001461440d57506001600160801b039150602001511690565b5460f81c61441f57506143a39061382c565b6143a391506001600160801b036040818351169201511690613397565b909291614447613635565b936001600160801b03928381169182156145535767016345785d8a000080821161451c578085116144e5575061449185614482819386614762565b16946020890195865284614762565b1691846144a86040890194808652828751166143a6565b1610156144cf576144c18491826144ca95511690613397565b91511690613397565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614566816132ad565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612a9e57614349926040525b6001600160a01b031690614611600080836020829551910182875af161460a61434b565b9084614811565b90815191821515928361465a575b5050506146295750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a81576020015190811591821503610666575038808061461f565b670de0b6b3a764000091600019838309928083029283808610950394808603951461473e578285101561470257908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b50508092501561474c570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461480057670de0b6b3a764000090818310156147c957947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614850575080511561482657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061489b575b614861575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561485956fea164736f6c6343000817000a"; + bytes public constant BYTECODE_LOCKUP_TRANCHED = + hex"60c0346200046e57601f6200515138819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601e82527f5361626c696572205632204c6f636b7570205472616e63686564204e465400006020830152620000be62000473565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051614cbd908162000494823960805181613f56015260a05181818161303901526140560152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146133735750806306fdde03146132af578063081812fc14613290578063095ea7b3146131975780631400ecec146130f75780631c1cdd4c146130925780631e99d5691461307457806323b872dd1461305c5780632fe430411461302157806332fbe22b14612ed257806339a73c0314612e9157806340e58ee514612c06578063425d30dd14612bb557806342842e0e14612b7b57806342966c68146129a057806344267570146129795780634857501f146129035780634869e12d146128c85780634cc55e11146124555780635fe3b5671461242e5780636352211e146123fe5780636d0cee75146123fe57806370a082311461238e57806375829def146122fb5780637cad6cd11461222a5780637de6b1db146120035780637f5799f914611fa85780638659c27014611c59578063894e9a0d14611912578063897f362b146116625780638bad38dd146115e55780638f69b993146115495780639067b677146114f957806395d89b41146113ea578063a22cb4651461132d578063a6202bf214611230578063a80fc071146111de578063ad35efd41461117c578063b25645691461112b578063b88d4fde1461109e578063b8a3be6614611069578063b971302a1461101a578063bc063e1a14610ff7578063bc2be1be14610fa7578063c156a11d14610b19578063c87b56dd146109fd578063cc364f4814610965578063d4dbd20b14610913578063d511609f146108c7578063d975dfed1461087b578063e985e9c514610826578063ea5ead1914610744578063eac8f5b8146106f2578063f590c17614610690578063f851a4401461066a5763fdd46d601461028957600080fd5b3461066757606036600319011261066757600435906102a66134a2565b91604435926001600160801b0380851691828603610662576102c6613f4c565b838552600b9560209387855260ff600160408920015460a81c161561064b5785875287855260ff600160408920015460a01c16610633576001600160a01b039081841680156106095781156105f157878952600587528260408a2054169283821415806105e1575b6105bd5761033b89614863565b878116841161058b575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061036f9161488e565b858d5284845260408d20600201908282549160801b6001600160801b031916911617815561039c90613a68565b908084830151169181808251169160400151166103b89161368a565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361055c575b848c528252600160408c20015416946103fd818a886147d7565b604051908152a48033141580610552575b6104e4575b8333141590816104d9575b816104ce575b50610458575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104ca57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104b2575b808061042a565b6104bb906135ab565b6104c65782386104ab565b8280fd5b8380fd5b905083141538610424565b843b1515915061041e565b803b1561054e57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161053a575b5050610413565b610543906135ab565b61054e578438610533565b8480fd5b50803b151561040e565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103e3565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105eb8961476e565b1561032e565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106675780600319360112610667576001600160a01b036020915416604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db578160409160209352600b8352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760016040836001600160a01b039360209552600b855220015416604051908152f35b503461066757604036600319011261066757600435906107626134a2565b9161076c81614863565b92610775613f4c565b818352600b9360209185835260ff600160408720015460a81c161561080f5783855285835260ff600160408720015460a01c166107f7576001600160a01b0391828216928315610609576001600160801b03938483169081156105f157878952600587528260408a2054169283821415806105e1576105bd5761033b89614863565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106675760403660031901126106675761084061348c565b604061084a6134a2565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106675760203660031901126106675760ff6001604060043593848152600b60205220015460a81c16156106db576108b6602091614863565b6001600160801b0360405191168152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408260029260209452600b845220015460801c604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760036040836001600160801b039360209552600b855220015416604051908152f35b5034610667576020366003190112610667576004356000602060405161098a816135dc565b8281520152808252600b60205260ff600160408420015460a81c16156106db5760408281928152600b602052205464ffffffffff8251916109ca836135dc565b818160a01c16835260c81c1660208201526109fb825180926020908164ffffffffff91828151168552015116910152565bf35b503461066757602080600319360112610b0957600435610a1c81613c2a565b50826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610b0d578093610a8c575b5050610a88604051928284938452830190613467565b0390f35b909192503d8082843e610a9f8184613614565b8201918381840312610b095780519067ffffffffffffffff82116104c6570182601f82011215610b0957805191610ad583613636565b93610ae36040519586613614565b838552858484010111610667575090610b0191848085019101613444565b903880610a72565b5080fd5b604051903d90823e3d90fd5b503461066757604036600319011261066757600435610b366134a2565b610b3e613f4c565b818352600b9060209082825260ff600160408720015460a81c161561080f57838552600582526001600160a01b03918260408720541693843303610f8857610b8586614863565b906001600160801b039081831680158015610c25575b50505050505081811615610c0d5783610bb391613e07565b90811680610bd35760248460405190637e27328960e01b82526004820152fd5b8203610bdd578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c2d613f4c565b898b5282865260ff600160408d20015460a81c1615610f7157898b5282865260ff600160408d20015460a01c16610f5957881561060957610f4157888a52600585528660408b205416918289141580610f31575b610f0d57610c8e8a614863565b8481168311610edb5750908a949392918a86528087526040862093610cea610cc18760028d89541698015460801c61488e565b8d8952838a52600260408a200190836001600160801b031983549260801b169116178155613a68565b90610d06818a840151169282604081835116920151169061368a565b161115610eac575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d4d8186886147d7565b604051908152a48033141580610ea2575b610e38575b813314159081610e2d575b81610e22575b50610db1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b9b565b803b156104c657604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610e0a575b80610d7a565b610e13906135ab565b610e1e578538610e04565b8580fd5b905081141538610d74565b823b15159150610d6e565b803b156104ca57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e8e575b5050610d63565b610e97906135ab565b6104ca578338610e87565b50803b1515610d5e565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610d0e565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f3b8a61476e565b15610c81565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610667578060031936011261066757602060405167016345785d8a00008152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576040826001600160a01b039260209452600b8452205416604051908152f35b50346106675760203660031901126106675760ff600160406020936004358152600b855220015460a81c166040519015158152f35b5034610667576080366003190112610667576110b861348c565b6110c06134a2565b906064359067ffffffffffffffff82116104ca57366023830112156104ca57816004013592846110ef85613636565b936110fd6040519586613614565b8585523660248783010111610b09578561112896602460209301838801378501015260443591613abd565b80f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57600160408360ff9360209552600b855220015460b01c166040519015158152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576111b590613d80565b6040519060058110156111ca57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760026040836001600160801b039360209552600b855220015416604051908152f35b50346106675760203660031901126106675761124a61348c565b6001600160a01b0380835416338103611304575081169081835260026020526001600160801b036040842054169081156112d357816112a4918486526002602052604086206001600160801b0319815416905533906147d7565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106675760403660031901126106675761134761348c565b60243590811515809203610662576001600160a01b03169081156113b95733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757806003193601126106675760405190806004549160018360011c92600185169485156114ef575b60209586861081146114db578588528794939291879082156114b957505060011461145f575b505061144b92500383613614565b610a88604051928284938452830190613467565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8583106114a157505061144b9350820101388061143d565b80548389018501528794508693909201918101611489565b925093505061144b94915060ff191682840152151560051b820101388061143d565b602483634e487b7160e01b81526022600452fd5b93607f1693611417565b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5761158290613d80565b90600582101590816115c357600283149182156115d7575b82156115ae575b6020836040519015158152f35b9091506115c3575060046020911438806115a1565b80634e487b7160e01b602492526021600452fd5b50600383149150600061159a565b5034610667576020366003190112610667576004356001600160a01b03908181168091036104c65781835416338103611304575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b5034610667576020906003198281360112610b09576004359167ffffffffffffffff91828411610b095761012084360391820112610b09576116a2613f4c565b60c48401359060221901811215610b095783016004810135928311610b095760248101908360061b80360383136104ca576024906116df86613914565b956116ed6040519788613614565b8652878601920101913683116104ca57905b868383106118fa575050505081519061171782613914565b926117256040519485613614565b828452601f1961173484613914565b0186835b8281106118d65750505064ffffffffff804216936001600160801b03928361175f82613c4d565b51511683808b61176e85613c4d565b5101511688011660405191611782836135dc565b82528a82015261179188613c4d565b5261179b87613c4d565b5060019260015b83811061186d5750505050506117ba85600401613a9c565b916117c760248701613a9c565b916117d4604488016139b7565b6064880135926001600160a01b039081851680950361066757509288959261182598959261185a989561180c60846118659d01613ab0565b948161181a60a48c01613ab0565b976040519d8e61358e565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613962565b610100820152613fa8565b604051908152f35b8089838d8180826118928d6118838e9a8d613c5a565b51511696600019890190613c5a565b51015116916118a1868a613c5a565b510151160116604051916118b4836135dc565b82528d8201526118c4828c613c5a565b526118cf818b613c5a565b50016117a2565b6040516118e2816135dc565b60008152600083820152828289010152018790611738565b604091611907368561392c565b8152019101906116ff565b5034610667576020366003190112610667576060610140604051611935816135bf565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152611970613a49565b61012082015201526004358152600b60205260ff600160408320015460a81c1615611c41576004358152600b602052604081209060405191610140830183811067ffffffffffffffff821117611c2b57611a529160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613a68565b610120830152611a63600435613d80565b6005811015611c1757610140926002611b2f9214611c0c575b6101208101516001600160a01b0360a08301511664ffffffffff60408401511694606084015115159061010085015115159260c086015115159160e08701511515936001600160a01b03885116996080604064ffffffffff60208c015116946004358152600c602052209901511515926040519b611af98d6135bf565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e08601526101008501526101208401526139cb565b82820152610a88604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e081015115156101008501526101008101511515610120850152611bf861012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190613532565b826060820152611a7c565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461066757602080600319360112610b095760043567ffffffffffffffff81116104c657611c8c903690600401613501565b9190611c96613f4c565b83925b808410611ca4578480f35b611caf848284613991565b3593611cb9613f4c565b848652600b80855260ff90600190828260408b20015460a81c1615611f9157878952808752604089208281015460a01c841615611d085760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611f7957611d3981600052600b6020526001600160a01b0360406000205416331490565b15611f5957611d4781613c6e565b818a52828952611d5c600260408c2001613a68565b906001600160801b0395868351168783161015611f4157838c52848b5260408c205460f01c1615611f295791818a8c7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611dd0878b85611dc660409b879f9e9d9b8490511661368a565b970151169061368a565b85835286845287832098895490600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316178b5560038c84169b8c15611f10575b019b87169b8c6001600160801b03198254161790556001600160a01b03808093169a8b96600589522054169889965260408d2001541694611e558b85886147d7565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611eb9575b505050505050600101929190611c99565b813b15610e1e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611efc575b80808080611ea8565b611f05906135ab565b61054e578438611ef3565b828101600160a01b60ff60a01b19825416179055611e13565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57604082611fef92610a889452600c602052206139cb565b604051918291602083526020830190613532565b503461066757602080600319360112610b095760043590612022613f4c565b818352600b815260ff600160408520015460a81c16156122135761204582613d80565b60058110156121ff576004810361206e5760248360405190634a5541ef60e01b82526004820152fd5b6003810361208e576024836040519063fe19f19f60e01b82526004820152fd5b6002146121e7576120b582600052600b6020526001600160a01b0360406000205416331490565b156121c857818352600b815260ff604084205460f01c16156121b057818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b612158575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104c657816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af161219c575b80612129565b6121a5906135ab565b6104c6578238612196565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610667576020366003190112610667576004356001600160a01b03908181168091036104c657818354163381036113045750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116122e75760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b50346106675760203660031901126106675761231561348c565b9080546001600160a01b0380821693338503612367576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610667576020366003190112610667576001600160a01b036123b061348c565b1680156123cd578160409160209352600683522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757602036600319011261066757602061241d600435613c2a565b6001600160a01b0360405191168152f35b503461066757806003193601126106675760206001600160a01b0360015416604051908152f35b50346106675760403660031901126106675767ffffffffffffffff6004358181116104c657612488903690600401613501565b90916024359081116104ca576124a2903690600401613501565b6124aa613f4c565b80830361289157845b8381106124be578580f35b6124c9818587613991565b35906124d6818688613991565b35875260056020526001600160a01b036040882054166124ff6124fa838688613991565b6139b7565b90612508613f4c565b838952600b60205260ff600160408b20015460a81c161561080f57838952600b60205260ff600160408b20015460a01c166107f7578015610609576001600160801b038216156128795783895260056020526001600160a01b0360408a205416918282141580612869575b6128455761258085614863565b6001600160801b0381166001600160801b03831611612815575090899291858452600b60205260408420926125fd6001600160a01b03855416946002809101546001600160801b036001600160801b03196125df87608094851c61488e565b938c8b52600b60205260408b2001938454931b169116178155613a68565b6001600160801b03612621816020840151169282604081835116920151169061368a565b1611156127e4575b868552600b6020526001600160a01b036001604087200154166126566001600160801b03841685836147d7565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806127da575b612770575b833314159081612765575b8161275a575b506126e8575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016124b3565b823b156104ca57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612742575b80806126b1565b61274b906135ab565b61275657863861273b565b8680fd5b9050831415386126ab565b843b151591506126a5565b803b1561054e57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af16127c6575b505061269a565b6127cf906135ab565b61054e5784386127bf565b50803b1515612695565b868552600b6020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612629565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506128738561476e565b15612573565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106675760203660031901126106675760ff6001604060043593848152600b60205220015460a81c16156106db576108b6602091614a57565b50346106675760203660031901126106675760043590818152600b60205260ff600160408320015460a81c1615612213578061293e83613d80565b926005841015611c175760026020940361295f575b50506040519015158152f35b8152600b8352604090205460f01c60ff1690503880612953565b503461066757806003193601126106675760206001600160a01b03600a5416604051908152f35b503461066757602080600319360112610b0957600435906129bf613f4c565b818352600b815260ff600160408520015460a81c161561221357818352600b815260ff600160408520015460a01c1615612b4a576129fc8261476e565b156121c85781600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c16159081612b40575b5080612b38575b612b20577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526005835260406000205416918215928315612ae5575b846000526005825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612acd575080f35b60249060405190637e27328960e01b82526004820152fd5b612b0685600052600760205260406000206001600160a01b03198154169055565b806000526006825260406000206000198154019055612a7b565b60248360405190630da9b01360e01b82526004820152fd5b506000612a3b565b9050151538612a34565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757612b8a366134cc565b60405191602083019383851067ffffffffffffffff861117611c2b5761112894604052858452613abd565b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57600160408360ff9360209552600b855220015460a01c166040519015158152f35b503461066757602090816003193601126106675760043590612c26613f4c565b818152600b9283815260ff600160408420015460a81c1615612e7a5782825283815260408220600181015460a01c60ff1615612c745760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611f7957612c9f81600052600b6020526001600160a01b0360406000205416331490565b15611f5957612cad81613c6e565b93818452808352612cc360026040862001613a68565b916001600160801b03938484511685881610156121e75781865282815260ff604087205460f01c16156121b057612d07878683611dc68a9b838a9c9b9c511661368a565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612e60575b01988716988981546001600160801b0319161790556001600160a01b038096168097600585528760408b205416978893865260408b20600101541693612d938c84876147d7565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612e0f578480f35b823b1561054e576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612e51575b81818080808480f35b612e5a906135ab565b81612e48565b60018101600160a01b60ff60a01b19825416179055612d4c565b6024836040519062b8e7e760e51b82526004820152fd5b5034610667576020366003190112610667576001600160801b0360406020926001600160a01b03612ec061348c565b16815260028452205416604051908152f35b5034610667576003199060203683018113610b09576004359167ffffffffffffffff93848411610b095761014090843603011261066757612f11613f4c565b60405193612f1e8561358e565b612f2a846004016134b8565b8552612f38602485016134b8565b6020860152612f4960448501613652565b6040860152612f5a606485016134b8565b6060860152612f6b60848501613581565b6080860152612f7c60a48501613581565b60a0860152612f8d60c48501613902565b60c086015260e4840135908111610b095783019136602384011215610b09576004830135612fba81613914565b93612fc86040519586613614565b8185526024602086019260061b820101933685116106675750602401905b8382106130085760206118658861185a898960e0840152610104369101613962565b82604091613016368561392c565b815201910190612fe6565b503461066757806003193601126106675760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346106675761112861306e366134cc565b916136b9565b50346106675780600319360112610667576020600954604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576130cb90613d80565b9060058210156115c357602082158381156130ec575b506040519015158152f35b6001915014826130e1565b50346106675760203660031901126106675760043590818152600b60205260ff600160408320015460a81c161561221357602091604082828152600b85522060ff815460f01c1680613185575b61315c575b50506001600160801b0360405191168152f35b61317e92506001600160801b0360026131789201541691613c6e565b9061368a565b3880613149565b5060ff600182015460a01c1615613144565b5034610667576040366003190112610667576131b161348c565b6024356131bd81613c2a565b3315158061327d575b80613253575b6132235781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600760205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260086020526040842033855260205260ff604085205416156131cc565b50336001600160a01b03821614156131c6565b503461066757602036600319011261066757602061241d600435613666565b503461066757806003193601126106675760405190806003549160018360011c9260018516948515613369575b60209586861081146114db578588528794939291879082156114b957505060011461330f57505061144b92500383613614565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b85831061335157505061144b9350820101388061143d565b80548389018501528794508693909201918101613339565b93607f16936132dc565b905034610b09576020366003190112610b09576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104c657602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561341a575b81156133f0575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386133e9565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506133e2565b60005b8381106134575750506000910152565b8181015183820152602001613447565b9060209161348081518092818552858086019101613444565b601f01601f1916010190565b600435906001600160a01b038216820361066257565b602435906001600160a01b038216820361066257565b35906001600160a01b038216820361066257565b6060906003190112610662576001600160a01b0390600435828116810361066257916024359081168103610662579060443590565b9181601f840112156106625782359167ffffffffffffffff8311610662576020808501948460051b01011161066257565b90815180825260208080930193019160005b828110613552575050505090565b835180516001600160801b0316865282015164ffffffffff168583015260409094019392810192600101613544565b3590811515820361066257565b610120810190811067ffffffffffffffff821117611c2b57604052565b67ffffffffffffffff8111611c2b57604052565b610160810190811067ffffffffffffffff821117611c2b57604052565b6040810190811067ffffffffffffffff821117611c2b57604052565b6060810190811067ffffffffffffffff821117611c2b57604052565b90601f8019910116810190811067ffffffffffffffff821117611c2b57604052565b67ffffffffffffffff8111611c2b57601f01601f191660200190565b35906001600160801b038216820361066257565b61366f81613c2a565b5060005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116136a357565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156138ea5760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c161590816138e0575b50806138d8575b6138c1578685526005815282848620541694873315159384613811575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876137d9575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036137ab5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6137fa82600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055613747565b91929380915090613880575b1561382b579087839261371e565b848887613848576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156138a5575b8061381d575087825260078352338486842054161461381d565b5085825260088352848220338352835260ff858320541661388b565b602487855190630da9b01360e01b82526004820152fd5b506001613701565b90501515386136fa565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361066257565b67ffffffffffffffff8111611c2b5760051b60200190565b919082604091031261066257604051613944816135dc565b602061395d81839561395581613652565b855201613902565b910152565b91908260409103126106625760405161397a816135dc565b6020808294613988816134b8565b84520135910152565b91908110156139a15760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036106625790565b9081546139d781613914565b926040936139e86040519182613614565b82815280946020809201926000526020600020906000935b858510613a0f57505050505050565b60018481928451613a1f816135dc565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613a00565b60405190613a56826135f8565b60006040838281528260208201520152565b90604051613a75816135f8565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b03811681036106625790565b3580151581036106625790565b9190613aca8282856136b9565b803b613ad7575b50505050565b613b336001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613467565b03906020816000938185885af190829082613bc9575b5050613b805782613b58614833565b8051919082613b795760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613bb1575038808080613ad1565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613c22575b81613be660209383613614565b81010312610b095751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106675750903880613b49565b3d9150613bd9565b8060005260056020526001600160a01b0360406000205416908115612acd575090565b8051156139a15760200190565b80518210156139a15760209160051b010190565b64ffffffffff80421691600090808252602091600c602052613c92604082206139cb565b9185856020613ca086613c4d565b5101511611613d77578152600b602052604081208585825460c81c161115613d6157506001600160801b039485613cd684613c4d565b5151169583519260019360011015613d4d5750949392919084602060408501510151169581866001985b161115613d11575050505050505090565b909181879881613d258798999a8598613c5a565b5151160116970191868087613d3a8689613c5a565b5101511697829392919796959498613d00565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b80600052600b602052604060002060ff600182015460a01c16600014613da7575050600490565b805460f81c613e00575460a01c64ffffffffff164210613dfa57613dca81613c6e565b90600052600b6020526001600160801b038060026040600020015416911610600014613df557600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613f42575b5080613f37575b613f20579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613ee8575b169283613ed2575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613eae565b613f0986600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613ea6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613e45565b9050151538613e3e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613f7e57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156147625760009061472e575b61402a91506001600160801b036040850151169060206101008601510151916148a9565b6001600160801b0381511660e084015164ffffffffff60c086015116821561470457815180156146da577f000000000000000000000000000000000000000000000000000000000000000081116146a9575064ffffffffff602061408d84613c4d565b510151168110156146525750600090819082815184905b8082106145c1575050505064ffffffffff421664ffffffffff82168110156145815750506001600160801b031680820361454a5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206142378951996000198b0190613c5a565b51015160c81b169560f01b16911617171717845560005b8181106144a5575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b0360208301511680156138ea576142d9866001600160a01b0392613e07565b166144745761430e6001600160a01b036060840151166001600160801b038084511681602086015116011690309033906149e8565b6001600160801b0360408201511680614444575b507fd1aaaf57e122e7b428e079232d56f44a4f2877a9dcb386ea1a442f758dd6e34f6144016001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661443961441960808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6143ad8c6135dc565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190613532565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b61446e906001600160a01b036060850151166001600160a01b0361010086015151169033906149e8565b38614322565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906144c28160e0870151613c5a565b51825468010000000000000000811015611c2b57600181018085558110156139a157600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b169216171790550161424e565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936145e5906001600160801b036145dc8588613c5a565b5151169061488e565b9364ffffffffff8060206145f98685613c5a565b51015116941680851115614615575060018493019092916140a4565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061466384613c4d565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161475a575b8161474860209383613614565b810103126106625761402a9051614006565b3d915061473b565b6040513d6000823e3d90fd5b60009080825260056020526001600160a01b0380604084205416928333149384156147b3575b505082156147a157505090565b9091506147ae3392613666565b161490565b60ff9294509060409181526008602052818120338252602052205416913880614794565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526148319161482c606483613614565b614ad2565b565b3d1561485e573d9061484482613636565b916148526040519384613614565b82523d6000602084013e565b606090565b61488b9061487081614a57565b90600052600b60205260026040600020015460801c9061368a565b90565b9190916001600160801b03808094169116019182116136a357565b9092916148b4613a49565b936001600160801b03928381169182156149c05767016345785d8a00008082116149895780851161495257506148fe856148ef819386614b6e565b16946020890195865284614b6e565b16918461491560408901948086528287511661488e565b16101561493c5761492e8491826149379551169061368a565b9151169061368a565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516149d3816135f8565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611c2b5761483192604052614ad2565b80600052600b602052614a706002604060002001613a68565b81600052600b602052604060002060ff600182015460a01c16600014614aa357506001600160801b039150602001511690565b5460f81c614ab5575061488b90613c6e565b61488b91506001600160801b03604081835116920151169061368a565b6001600160a01b031690614afd600080836020829551910182875af1614af6614833565b9084614c1d565b908151918215159283614b46575b505050614b155750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610b095760200151908115918215036106675750388080614b0b565b90919060001983820983820291828083109203918083039214614c0c57670de0b6b3a76400009081831015614bd557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614c5c5750805115614c3257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614ca7575b614c6d575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15614c6556fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"6080806040523461001757615ea390816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661568d565b91601e604660ff61030b8460146050848d60081c1606011661568d565b981606011661568d565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615014565b169061517d565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff80911691166154c8565b610120516101805190929161059d602161053a606461053381870661599a565b950461568d565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615aa6565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b600081528661596e565b156147c9576090945b6106fa8661568d565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615da2565b6109ec82615e20565b808211156147c15750945b610a0287870161568d565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615da2565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615da2565b610d1b82615e20565b808211156147b95750935b610d326028860161568d565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615113565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615a6d565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615a6d565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615a6d565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615a6d565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615113565b92611ce9611ce3614d0b565b8961596e565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615ce6565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615ce6565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615d4e565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615d4e565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461568d565b9461568d565b9761568d565b9161568d565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561568d565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561568d565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b61016051614104906157de565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e08190526157de565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b9061596e565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d848761595d565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660409081516395d89b4160e01b8152600081600481855afa90811561500957600091614fe6575b50614ee88351614eb8816149de565b601181527f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000060208201528261596e565b15614f2657505051614ef9816149de565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b614f648351614f34816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000060208201528261596e565b15614fa257505051614f75816149de565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b614fe29083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61500391503d806000833e614ffb81836149fa565b810190614bce565b38614ea9565b83513d6000823e3d90fd5b60405160208101907f313ce5670000000000000000000000000000000000000000000000000000000082526004815261504c816149de565b6000928392839251915afa61505f614b9e565b9080615096575b156150925760208180518101031261508e57602001519060ff8216820361508b575090565b80fd5b5080fd5b5090565b506020815114615066565b604051906150ae826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b604051906150e7826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b9061517b92949360405195869260209461513581518092888089019101614909565b840161514982518093888085019101614909565b0161515c82518093878085019101614909565b0161516f82518093868085019101614909565b010380855201836149fa565b565b801561548d5760009180615468575090505b60019080828110156151f9575050506151a66150da565b614c2d6022604051836151c3829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c68000111561540b5760409081519060a0820182811067ffffffffffffffff821117614402578084526152308161498a565b600081528252825190615242826149de565b8482526020917f4b000000000000000000000000000000000000000000000000000000000000008382015282840152835161527c816149de565b8581527f4d00000000000000000000000000000000000000000000000000000000000000838201528484015283516152b3816149de565b8581527f420000000000000000000000000000000000000000000000000000000000000083820152606084015283516152eb816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b6153df575b50845194615332866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b8281106153cc57505050506153ad6153b3917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526153a8866149de565b61568d565b9161599a565b916005851015614b6c57614c2d9460051b015192615113565b8181018401518882018501528301615363565b9591926103e89081851061540257508680916064600a8704069504930196615320565b93929650615325565b50506154156150a1565b614c2d602860405183615432829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a91821561547957500461518f565b80634e487b7160e01b602492526012600452fd5b505060405161549b816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061553057506154dd6150da565b614c2d6026604051836154fa829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f81116155ff57600181036155bc57614c2d6020615584604051615555816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361568d565b604051938161559c8693518092868087019101614909565b82016155b082518093868085019101614909565b010380845201826149fa565b614c2d60206155846040516155d0816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361568d565b506156086150a1565b614c2d602a60405183615625829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b9061566582614b82565b61567260405191826149fa565b8281528092615683601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000808210156157d0575b506d04ee2d6d415b85acef8100000000808310156157c1575b50662386f26fc10000808310156157b2575b506305f5e100808310156157a3575b5061271080831015615794575b506064821015615784575b600a8092101561577a575b6001908160216157256001870161565b565b95860101905b615737575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157755791908261572b565b615730565b9160010191615713565b9190606460029104910191615708565b600491939204910191386156fd565b600891939204910191386156f0565b601091939204910191386156e1565b602091939204910191386156cf565b6040935081049150386156b6565b805115615949576040516157f1816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159335760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116810361593357615890906002959492951b61565b565b936020850193839284518501935b8481106158e05750505050506003905106806001146158cd576002146158c2575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061589e565b634e487b7160e01b600052601160045260246000fd5b506040516159568161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615984575050505090565b6020929394508201209201201438808080615730565b806159ac57506040516159568161498a565b600a811015615a11576159be9061568d565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a018151809260208686019101614909565b81010360028101845201826149fa565b615a1a9061568d565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a5d8151809260208686019101614909565b81010360018101845201826149fa565b60405190615a7a826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cd857615ab4615a6d565b9061271090810390811161593357614c2d91615ad26101369261568d565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615b5e815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615be682518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615c4782518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159568161498a565b603061517b919392936040519481615d08879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615d3f8251809360208785019101614909565b010360108101855201836149fa565b602561517b919392936040519481615d70879351809260208087019101614909565b820164010714051160dd1b6020820152615d938251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e1857906000916000915b818310615dc757505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615dfa878561595d565b511614615e10575b600d01936001019190615db5565b849350615e02565b505050600090565b60009080518015615e1857906000916000915b818310615e455750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e78878561595d565b511614615e8e575b601001936001019190615e33565b849350615e8056fea164736f6c6343000817000a"; + hex"6080806040523461001757615f2090816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661570a565b91601e604660ff61030b8460146050848d60081c1606011661570a565b981606011661570a565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615091565b16906151fa565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff8091169116615545565b610120516101805190929161059d602161053a6064610533818706615a17565b950461570a565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615b23565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b60008152866159eb565b156147c9576090945b6106fa8661570a565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b6109ec82615e9d565b808211156147c15750945b610a0287870161570a565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615e1f565b610d1b82615e9d565b808211156147b95750935b610d326028860161570a565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615190565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615aea565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615aea565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615aea565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615aea565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615190565b92611ce9611ce3614d0b565b896159eb565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615d63565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615d63565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615dcb565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615dcb565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461570a565b9461570a565b9761570a565b9161570a565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561570a565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561570a565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b610160516141049061585b565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e081905261585b565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b906159eb565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d84876159da565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa92831561508657600093615063575b50815192614eb6846149de565b60118452614eeb6020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159eb565b15614f295750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614f1f836149de565b600d835282015290565b614f668351614f37816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159eb565b15614fa45750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614f9a836149de565b600e835282015290565b614fe18351614fb2816149de565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159eb565b1561501f5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191615015836149de565b600f835282015290565b61505f9083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61507f91933d8091833e61507781836149fa565b810190614bce565b9138614ea9565b82513d6000823e3d90fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150c9816149de565b6000928392839251915afa6150dc614b9e565b9080615113575b1561510f5760208180518101031261510b57602001519060ff82168203615108575090565b80fd5b5080fd5b5090565b5060208151146150e3565b6040519061512b826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615164826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151f89294936040519586926020946151b281518092888089019101614909565b84016151c682518093888085019101614909565b016151d982518093878085019101614909565b016151ec82518093868085019101614909565b010380855201836149fa565b565b801561550a57600091806154e5575090505b600190808281101561527657505050615223615157565b614c2d602260405183615240829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c6800011156154885760409081519060a0820182811067ffffffffffffffff821117614402578084526152ad8161498a565b6000815282528251906152bf826149de565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152f9816149de565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615330816149de565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615368816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545c575b508451946153af866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615449575050505061542a615430917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615425866149de565b61570a565b91615a17565b916005851015614b6c57614c2d9460051b015192615190565b81810184015188820185015283016153e0565b9591926103e89081851061547f57508680916064600a870406950493019661539d565b939296506153a2565b505061549261511e565b614c2d6028604051836154af829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a9182156154f657500461520c565b80634e487b7160e01b602492526012600452fd5b5050604051615518816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155ad575061555a615157565b614c2d602660405183615577829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f811161567c576001810361563957614c2d60206156016040516155d2816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570a565b60405193816156198693518092868087019101614909565b820161562d82518093868085019101614909565b010380845201826149fa565b614c2d602061560160405161564d816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570a565b5061568561511e565b614c2d602a604051836156a2829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b906156e282614b82565b6156ef60405191826149fa565b8281528092615700601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561584d575b506d04ee2d6d415b85acef81000000008083101561583e575b50662386f26fc100008083101561582f575b506305f5e10080831015615820575b5061271080831015615811575b506064821015615801575b600a809210156157f7575b6001908160216157a2600187016156d8565b95860101905b6157b4575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f2579190826157a8565b6157ad565b9160010191615790565b9190606460029104910191615785565b6004919392049101913861577a565b6008919392049101913861576d565b6010919392049101913861575e565b6020919392049101913861574c565b604093508104915038615733565b8051156159c65760405161586e816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159b05760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159b05761590d906002959492951b6156d8565b936020850193839284518501935b84811061595d57505050505060039051068060011461594a5760021461593f575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061591b565b634e487b7160e01b600052601160045260246000fd5b506040516159d38161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615a01575050505090565b60209293945082012092012014388080806157ad565b80615a2957506040516159d38161498a565b600a811015615a8e57615a3b9061570a565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7e8151809260208686019101614909565b81010360028101845201826149fa565b615a979061570a565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ada8151809260208686019101614909565b81010360018101845201826149fa565b60405190615af7826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d5557615b31615aea565b906127109081039081116159b057614c2d91615b4f6101369261570a565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bdb815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c6382518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cc482518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159d38161498a565b60306151f8919392936040519481615d85879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dbc8251809360208785019101614909565b010360108101855201836149fa565b60256151f8919392936040519481615ded879351809260208087019101614909565b820164010714051160dd1b6020820152615e108251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e9557906000916000915b818310615e4457505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e7787856159da565b511614615e8d575b600d01936001019190615e32565b849350615e7f565b505050600090565b60009080518015615e9557906000916000915b818310615ec25750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ef587856159da565b511614615f0b575b601001936001019190615eb0565b849350615efd56fea164736f6c6343000817000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS @@ -60,7 +63,7 @@ contract Precompiles { public returns (ISablierV2LockupDynamic lockupDynamic) { - uint256 maxSegmentCount = MAX_SEGMENT_COUNT; + uint256 maxSegmentCount = MAX_COUNT; lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, maxSegmentCount); } @@ -88,7 +91,7 @@ contract Precompiles { public returns (ISablierV2LockupDynamic lockupDynamic) { - lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, nftDescriptor, MAX_SEGMENT_COUNT); + lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, nftDescriptor, MAX_COUNT); } /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. @@ -144,6 +147,71 @@ contract Precompiles { ); } + /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode, passing a default value for the + /// `maxTrancheCount` parameter. + /// @dev Notes: + /// - A default value is passed for `maxTrancheCount`. + /// - A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. + function deployLockupTranched( + address initialAdmin, + ISablierV2Comptroller initialComptroller + ) + public + returns (ISablierV2LockupTranched lockupTranched) + { + uint256 maxTrancheCount = MAX_COUNT; + lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, maxTrancheCount); + } + + /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. + /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. + function deployLockupTranched( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + uint256 maxTrancheCount + ) + public + returns (ISablierV2LockupTranched lockupTranched) + { + ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); + lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, nftDescriptor, maxTrancheCount); + } + + /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. + /// @dev A default value is passed for `maxTrancheCount`. + function deployLockupTranched( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + ISablierV2NFTDescriptor nftDescriptor + ) + public + returns (ISablierV2LockupTranched lockupTranched) + { + lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, nftDescriptor, MAX_COUNT); + } + + /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. + function deployLockupTranched( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + ISablierV2NFTDescriptor nftDescriptor, + uint256 maxTrancheCount + ) + public + returns (ISablierV2LockupTranched lockupTranched) + { + bytes memory creationBytecode = bytes.concat( + BYTECODE_LOCKUP_TRANCHED, abi.encode(initialAdmin, initialComptroller, nftDescriptor, maxTrancheCount) + ); + assembly { + lockupTranched := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require( + address(lockupTranched) != address(0), + "Sablier V2 Precompiles: deployment failed for LockupTranched contract" + ); + } + /// @notice Deploys {SablierV2NFTDescriptor} from precompiled bytecode. function deployNFTDescriptor() public returns (ISablierV2NFTDescriptor nftDescriptor) { bytes memory bytecode = BYTECODE_NFT_DESCRIPTOR; @@ -167,6 +235,7 @@ contract Precompiles { ISablierV2Comptroller comptroller, ISablierV2LockupDynamic lockupDynamic, ISablierV2LockupLinear lockupLinear, + ISablierV2LockupTranched lockupTranched, ISablierV2NFTDescriptor nftDescriptor ) { @@ -174,5 +243,6 @@ contract Precompiles { nftDescriptor = deployNFTDescriptor(); lockupDynamic = deployLockupDynamic(initialAdmin, comptroller); lockupLinear = deployLockupLinear(initialAdmin, comptroller); + lockupTranched = deployLockupTranched(initialAdmin, comptroller); } } diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 15d2768ee..164deba46 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -6,6 +6,7 @@ import { LibString } from "solady/src/utils/LibString.sol"; import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; @@ -33,7 +34,7 @@ contract Precompiles_Test is Base_Test { ISablierV2Comptroller comptroller = precompiles.deployComptroller(users.admin); address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, comptroller, nftDescriptor)); address expectedLockupDynamic = - address(deployOptimizedLockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_SEGMENT_COUNT())); + address(deployOptimizedLockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT())); bytes memory expectedLockupDynamicCode = adjustBytecode(expectedLockupDynamic.code, expectedLockupDynamic, actualLockupDynamic); assertEq(actualLockupDynamic.code, expectedLockupDynamicCode, "bytecodes mismatch"); @@ -48,6 +49,17 @@ contract Precompiles_Test is Base_Test { assertEq(actualLockupLinear.code, expectedLockupLinearCode, "bytecodes mismatch"); } + function test_DeployLockupTranched() external onlyTestOptimizedProfile { + ISablierV2Comptroller comptroller = precompiles.deployComptroller(users.admin); + address actualLockupTranched = + address(precompiles.deployLockupTranched(users.admin, comptroller, nftDescriptor)); + address expectedLockupTranched = + address(deployOptimizedLockupTranched(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT())); + bytes memory expectedLockupTranchedCode = + adjustBytecode(expectedLockupTranched.code, expectedLockupTranched, actualLockupTranched); + assertEq(actualLockupTranched.code, expectedLockupTranchedCode, "bytecodes mismatch"); + } + function test_DeployNFTDescriptor() external onlyTestOptimizedProfile { address actualNFTDescriptor = address(precompiles.deployNFTDescriptor()); address expectedNFTDescriptor = address(deployOptimizedNFTDescriptor()); @@ -59,6 +71,7 @@ contract Precompiles_Test is Base_Test { ISablierV2Comptroller actualComptroller, ISablierV2LockupDynamic actualLockupDynamic, ISablierV2LockupLinear actualLockupLinear, + ISablierV2LockupTranched actualLockupTranched, ISablierV2NFTDescriptor actualNFTDescriptor ) = precompiles.deployCore(users.admin); @@ -66,8 +79,9 @@ contract Precompiles_Test is Base_Test { ISablierV2Comptroller expectedComptroller, ISablierV2LockupDynamic expectedLockupDynamic, ISablierV2LockupLinear expectedLockupLinear, + ISablierV2LockupTranched expectedLockupTranched, ISablierV2NFTDescriptor expectedNFTDescriptor - ) = deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT()); + ) = deployOptimizedCore(users.admin, defaults.MAX_COUNT(), defaults.MAX_COUNT()); bytes memory expectedLockupDynamicCode = adjustBytecode( address(expectedLockupDynamic).code, address(expectedLockupDynamic), address(actualLockupDynamic) @@ -77,9 +91,14 @@ contract Precompiles_Test is Base_Test { address(expectedLockupLinear).code, address(expectedLockupLinear), address(actualLockupLinear) ); + bytes memory expectedLockupTranchedCode = adjustBytecode( + address(expectedLockupTranched).code, address(expectedLockupTranched), address(actualLockupTranched) + ); + assertEq(address(actualComptroller).code, address(expectedComptroller).code, "bytecodes mismatch"); assertEq(address(actualLockupDynamic).code, expectedLockupDynamicCode, "bytecodes mismatch"); assertEq(address(actualLockupLinear).code, expectedLockupLinearCode, "bytecodes mismatch"); + assertEq(address(actualLockupTranched).code, expectedLockupTranchedCode, "bytecodes mismatch"); assertEq(address(actualNFTDescriptor).code, address(expectedNFTDescriptor).code, "bytecodes mismatch"); } diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 4e4997f55..736988ece 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -7,7 +7,7 @@ import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol"; import { Vm } from "@prb/test/src/PRBTest.sol"; import { StdUtils } from "forge-std/src/StdUtils.sol"; -import { LockupDynamic } from "../../src/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; abstract contract Utils is StdUtils, PRBMathUtils { /// @dev The virtual address of the Foundry VM. @@ -54,6 +54,27 @@ abstract contract Utils is StdUtils, PRBMathUtils { } } + /// @dev Turns the tranches with durations into canonical tranches, which have timestamps. + function getTranchesWithTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + internal + view + returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) + { + unchecked { + tranchesWithTimestamps = new LockupTranched.Tranche[](tranches.length); + tranchesWithTimestamps[0] = LockupTranched.Tranche({ + amount: tranches[0].amount, + timestamp: getBlockTimestamp() + tranches[0].duration + }); + for (uint256 i = 1; i < tranches.length; ++i) { + tranchesWithTimestamps[i] = LockupTranched.Tranche({ + amount: tranches[i].amount, + timestamp: tranchesWithTimestamps[i - 1].timestamp + tranches[i].duration + }); + } + } + } + /// @dev Checks if the Foundry profile is "test-optimized". function isTestOptimizedProfile() internal returns (bool) { string memory profile = vm.envOr({ name: "FOUNDRY_PROFILE", defaultValue: string("default") }); From b835fab1cd459a5033e29ca921a43a598cc95513 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 5 Mar 2024 14:29:06 +0000 Subject: [PATCH 051/132] ci: schedule precompile tests to mon, wed and fri --- .github/workflows/ci-fork.yml | 12 ++++++++++-- .github/workflows/ci.yml | 8 -------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-fork.yml b/.github/workflows/ci-fork.yml index ab463578a..1de1165e0 100644 --- a/.github/workflows/ci-fork.yml +++ b/.github/workflows/ci-fork.yml @@ -1,4 +1,4 @@ -name: "CI Fork tests" +name: "CI Fork and Util tests" on: schedule: @@ -21,4 +21,12 @@ jobs: foundry-profile: "test-optimized" fuzz-seed: true match-path: "test/fork/**/*.sol" - name: "Fork tests" \ No newline at end of file + name: "Fork tests" + + test-utils: + needs: ["lint", "build"] + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-profile: "test-optimized" + match-path: "test/utils/**/*.sol" + name: "Utils tests" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b538fce79..c849781c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,6 @@ jobs: match-path: "test/integration/**/*.sol" name: "Integration tests" - test-utils: - needs: ["lint", "build"] - uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" - with: - foundry-profile: "test-optimized" - match-path: "test/utils/**/*.sol" - name: "Utils tests" - test-invariant: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" From 978a87ce70357272caf00b303defdab3840f11cf Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 6 Mar 2024 14:27:06 +0200 Subject: [PATCH 052/132] feat: add SablierV2LockupTranched in scripts --- script/DeployCore.s.sol | 4 +++ script/DeployCore2.s.sol | 6 ++++- script/DeployCore3.s.sol | 8 ++++-- script/DeployDeterministicCore.s.sol | 4 +++ script/DeployDeterministicCore2.s.sol | 6 ++++- script/DeployDeterministicCore3.s.sol | 8 ++++-- .../DeployDeterministicLockupTranched.s.sol | 27 +++++++++++++++++++ script/DeployLockupTranched.s.sol | 23 ++++++++++++++++ 8 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 script/DeployDeterministicLockupTranched.s.sol create mode 100644 script/DeployLockupTranched.s.sol diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index 8e6102348..8ab569184 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; @@ -14,6 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 2. {SablierV2NFTDescriptor} /// 3. {SablierV2LockupDynamic} /// 4. {SablierV2LockupLinear} +/// 5. {SablierV2LockupTranched} contract DeployCore is BaseScript { function run(address initialAdmin) public @@ -23,6 +25,7 @@ contract DeployCore is BaseScript { SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) { @@ -30,5 +33,6 @@ contract DeployCore is BaseScript { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 4bdfca0b4..16e10359a 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -5,6 +5,7 @@ import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescript import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol"; /// 1. {SablierV2Comptroller} /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { function run( address initialAdmin, @@ -24,11 +26,13 @@ contract DeployCore2 is BaseScript { returns ( SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched ) { comptroller = new SablierV2Comptroller(initialAdmin); lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol index 5d9d67990..2702b29dc 100644 --- a/script/DeployCore3.s.sol +++ b/script/DeployCore3.s.sol @@ -2,9 +2,10 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol"; /// 1. {SablierV2NFTDescriptor} /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} contract DeployCore3 is BaseScript { function run( address initialAdmin, @@ -24,11 +26,13 @@ contract DeployCore3 is BaseScript { returns ( SablierV2NFTDescriptor nftDescriptor, SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched ) { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 4f26d7e12..1e5a6a9da 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; @@ -14,6 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 2. {SablierV2NFTDescriptor} /// 3. {SablierV2LockupDynamic} /// 4. {SablierV2LockupLinear} +/// 5. {SablierV2LockupTranched} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { @@ -25,6 +27,7 @@ contract DeployDeterministicCore is BaseScript { SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) { @@ -33,5 +36,6 @@ contract DeployDeterministicCore is BaseScript { nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 312ccf98d..86d41ea84 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -5,6 +5,7 @@ import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescript import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol"; /// 1. {SablierV2Comptroller} /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { @@ -26,12 +28,14 @@ contract DeployDeterministicCore2 is BaseScript { returns ( SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched ) { bytes32 salt = constructCreate2Salt(); comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol index a96d8c733..30b7e49ca 100644 --- a/script/DeployDeterministicCore3.s.sol +++ b/script/DeployDeterministicCore3.s.sol @@ -2,9 +2,10 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol"; /// 1. {SablierV2NFTDescriptor} /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore3 is BaseScript { @@ -26,12 +28,14 @@ contract DeployDeterministicCore3 is BaseScript { returns ( SablierV2NFTDescriptor nftDescriptor, SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched ) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol new file mode 100644 index 000000000..9cb8d5c36 --- /dev/null +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; +import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. +/// @dev Reverts if the contract has already been deployed. +contract DeployDeterministicLockupTranched is BaseScript { + function run( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + broadcast + returns (SablierV2LockupTranched lockupTranched) + { + bytes32 salt = constructCreate2Salt(); + lockupTranched = + new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + } +} diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol new file mode 100644 index 000000000..09a718dc2 --- /dev/null +++ b/script/DeployLockupTranched.s.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; +import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; + +import { BaseScript } from "./Base.s.sol"; + +contract DeployLockupTranched is BaseScript { + function run( + address initialAdmin, + ISablierV2Comptroller initialComptroller, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + broadcast + returns (SablierV2LockupTranched lockupTranched) + { + lockupTranched = new SablierV2LockupTranched(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + } +} From afb412751a1fd4a5390d25e07dbff469c737cd04 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 6 Mar 2024 13:29:47 +0000 Subject: [PATCH 053/132] feat: include lockupTranched in deployment bash script --- shell/deploy-multi-chain.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 60fa9e561..e0cfd8a4a 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -165,7 +165,7 @@ else # load values from the terminal prompt echo -e "${WC}Missing '.env.deployment'. Provide details below: ${NC}\n" - # initialize chains with chain id and comptroller + # initialize chains with comptroller initialize_interactive fi @@ -199,10 +199,10 @@ for ((i=1; i<=$#; i++)); do # Sort the names sorted_names=($(printf "%s\n" "${names[@]}" | sort)) # Print the header - printf "\nSupported chains: \n%-20s %-20s\n" "Chain Name" "Chain ID" - printf "%-20s %-20s\n" "-----------" "-----------" + printf "\nSupported chains: \n%-20s %-20s\n" "Chain Name" + printf "%-20s %-20s\n" "-----------" - # Print the chains and their Chain IDs + # Print the supported chains for chain in "${sorted_names[@]}"; do IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}" @@ -217,7 +217,7 @@ for ((i=1; i<=$#; i++)); do INTERACTIVE=true echo -e "Interactive mode activated. Provide details below: \n" - # initialize only chain id and comptroller + # initialize only comptroller initialize_interactive fi @@ -330,9 +330,9 @@ for chain in "${provided_chains[@]}"; do # echo removes single quotes #################################################################### if [[ ${READ_ONLY} == true ]]; then - deployment_command+=("--sig" "'run(address,address,uint256)'") + deployment_command+=("--sig" "'run(address,address)'") else - deployment_command+=("--sig" "run(address,address,uint256)") + deployment_command+=("--sig" "run(address,address)") fi else # Construct the command @@ -344,9 +344,9 @@ for chain in "${provided_chains[@]}"; do deployment_command+=("--rpc-url" "${rpc_url}") if [[ ${READ_ONLY} == true ]]; then - deployment_command+=("--sig" "'run(address,address,uint256)'") + deployment_command+=("--sig" "'run(address,address)'") else - deployment_command+=("--sig" "run(address,address,uint256)") + deployment_command+=("--sig" "run(address,address)") fi fi @@ -389,12 +389,14 @@ for chain in "${provided_chains[@]}"; do # Extract and save contract addresses lockupDynamic_address=$(echo "${output}" | awk '/lockupDynamic: contract/{print $NF}') lockupLinear_address=$(echo "${output}" | awk '/lockupLinear: contract/{print $NF}') + lockupTranched_address=$(echo "${output}" | awk '/lockupTranched: contract/{print $NF}') nftDescriptor_address=$(echo "${output}" | awk '/nftDescriptor: contract/{print $NF}') # Save to the chain file { echo "SablierV2LockupDynamic = ${lockupDynamic_address}" echo "SablierV2LockupLinear = ${lockupLinear_address}" + echo "SablierV2LockupTranched = ${lockupTranched_address}" echo "SablierV2NFTDescriptor = ${nftDescriptor_address}" } >> "$chain_file" From 5e1814801160276644309ed70c24f2e7d4c828cc Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 7 Mar 2024 19:39:39 +0200 Subject: [PATCH 054/132] test: emit the correct element in the assertEq events --- test/utils/Assertions.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 7f9601642..5f2395315 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -107,8 +107,8 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { emit Log("Error: a == b not satisfied [LockupDynamic.Segment[]]"); - emit LogNamedArray(" Left", b); - emit LogNamedArray(" Right", a); + emit LogNamedArray(" Left", a); + emit LogNamedArray(" Right", b); fail(); } } @@ -125,8 +125,8 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { function assertEq(LockupTranched.Tranche[] memory a, LockupTranched.Tranche[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { emit Log("Error: a == b not satisfied [LockupTranched.Tranche[]]"); - emit LogNamedArray(" Left", b); - emit LogNamedArray(" Right", a); + emit LogNamedArray(" Left", a); + emit LogNamedArray(" Right", b); fail(); } } @@ -159,8 +159,8 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { function assertEqUint128(uint128 a, uint128 b) internal { if (a != b) { emit Log("Error: a == b not satisfied [uint128]"); - emit LogNamedUint128(" Left", b); - emit LogNamedUint128(" Right", a); + emit LogNamedUint128(" Left", a); + emit LogNamedUint128(" Right", b); fail(); } } @@ -177,8 +177,8 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { function assertEqUint40(uint40 a, uint40 b) internal { if (a != b) { emit Log("Error: a == b not satisfied [uint40]"); - emit LogNamedUint40(" Left", b); - emit LogNamedUint40(" Right", a); + emit LogNamedUint40(" Left", a); + emit LogNamedUint40(" Right", b); fail(); } } From 4b3b51562b27f2d7cbf294f332db8f8c3689f1d9 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 7 Mar 2024 19:26:17 +0000 Subject: [PATCH 055/132] ci: add fork tests to ci with 20 runs (#838) --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b538fce79..ec055182b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,17 @@ jobs: match-path: "test/invariant/**/*.sol" name: "Invariant tests" + test-fork: + needs: ["lint", "build"] + secrets: + RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }} + uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" + with: + foundry-fuzz-runs: 20 + foundry-profile: "test-optimized" + match-path: "test/fork/**/*.sol" + name: "Fork tests" + coverage: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" From c39f175cb44487f7ba859f6880a696231e5cb88b Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:45:33 +0200 Subject: [PATCH 056/132] Remove protocol fee (#839) * refactor: remove protocol fee refactor: remove comptroller test: update tests accordingly chore: update gas snapshot test: remove outdated comments * chore: update some inherited components comments * refactor: remove unused imports and improve natspec * docs: improve natspec --------- Co-authored-by: smol-ninja --- .gas-snapshot | 969 +++++++++++------- foundry.toml | 1 - script/DeployComptroller.s.sol | 12 - script/DeployCore.s.sol | 18 +- script/DeployCore2.s.sol | 16 +- script/DeployCore3.s.sol | 12 +- script/DeployDeterministicComptroller.s.sol | 15 - script/DeployDeterministicCore.s.sol | 18 +- script/DeployDeterministicCore2.s.sol | 16 +- script/DeployDeterministicCore3.s.sol | 12 +- script/DeployDeterministicLockupDynamic.s.sol | 5 +- script/DeployDeterministicLockupLinear.s.sol | 4 +- .../DeployDeterministicLockupTranched.s.sol | 5 +- script/DeployLockupDynamic.s.sol | 4 +- script/DeployLockupLinear.s.sol | 4 +- script/DeployLockupTranched.s.sol | 4 +- script/Init.s.sol | 2 +- shell/deploy-multi-chain.sh | 69 +- shell/prepare-artifacts.sh | 3 - shell/update-precompiles.sh | 2 - src/SablierV2Comptroller.sol | 71 -- src/SablierV2LockupDynamic.sol | 30 +- src/SablierV2LockupLinear.sol | 29 +- src/SablierV2LockupTranched.sol | 30 +- src/abstracts/SablierV2Base.sol | 85 -- src/abstracts/SablierV2Lockup.sol | 31 +- src/interfaces/ISablierV2Base.sol | 75 -- src/interfaces/ISablierV2Comptroller.sol | 52 - src/interfaces/ISablierV2Lockup.sol | 10 +- src/interfaces/ISablierV2LockupDynamic.sol | 6 +- src/interfaces/ISablierV2LockupLinear.sol | 6 +- src/interfaces/ISablierV2LockupTranched.sol | 4 +- src/libraries/Errors.sol | 13 +- src/libraries/Helpers.sol | 36 +- src/types/DataTypes.sol | 42 +- test/Base.t.sol | 15 +- test/fork/LockupDynamic.t.sol | 28 +- test/fork/LockupLinear.t.sol | 30 +- test/fork/LockupTranched.t.sol | 30 +- .../protocol-fees/protocolFees.t.sol | 32 - .../protocol-fees/protocolFees.tree | 5 - .../set-protocol-fee/setProtocolFee.s.sol | 58 -- .../set-protocol-fee/setProtocolFee.tree | 10 - .../lockup-dynamic/LockupDynamic.t.sol | 49 +- .../concrete/lockup-dynamic/constructor.t.sol | 8 +- .../createWithDurations.t.sol | 14 +- .../createWithDurations.tree | 1 - .../createWithTimestamps.t.sol | 46 +- .../createWithTimestamps.tree | 41 +- .../concrete/lockup-linear/LockupLinear.t.sol | 50 +- .../concrete/lockup-linear/constructor.t.sol | 14 +- .../createWithDurations.t.sol | 14 +- .../createWithDurations.tree | 1 - .../createWithTimestamps.t.sol | 36 +- .../createWithTimestamps.tree | 41 +- .../lockup-tranched/LockupTranched.t.sol | 49 +- .../lockup-tranched/constructor.t.sol | 8 +- .../createWithDurations.t.sol | 14 +- .../createWithDurations.tree | 1 - .../createWithTimestamps.t.sol | 46 +- .../createWithTimestamps.tree | 41 +- .../claimProtocolRevenues.t.sol | 60 -- .../claimProtocolRevenues.tree | 10 - .../protocol-revenues/protocolRevenues.t.sol | 29 - .../protocol-revenues/protocolRevenues.tree | 5 - .../set-comptroller/setComptroller.t.sol | 59 -- .../set-comptroller/setComptroller.tree | 10 - .../fuzz/comptroller/setProtocolFee.t.sol | 28 - .../fuzz/lockup-dynamic/LockupDynamic.t.sol | 4 +- .../lockup-dynamic/createWithDurations.t.sol | 19 +- .../lockup-dynamic/createWithTimestamps.t.sol | 65 +- .../lockup-dynamic/streamedAmountOf.t.sol | 19 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 3 - .../fuzz/lockup-linear/LockupLinear.t.sol | 4 +- .../lockup-linear/createWithDurations.t.sol | 14 +- .../lockup-linear/createWithTimestamps.t.sol | 62 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 3 - .../lockup-linear/withdrawableAmountOf.t.sol | 3 - .../fuzz/lockup-tranched/LockupTranched.t.sol | 4 +- .../lockup-tranched/createWithDurations.t.sol | 19 +- .../createWithTimestamps.t.sol | 66 +- .../lockup-tranched/streamedAmountOf.t.sol | 19 +- .../withdrawableAmountOf.t.sol | 3 - .../lockup-dynamic/createWithTimestamps.t.sol | 4 - .../lockup-linear/createWithTimestamps.t.sol | 4 - .../createWithTimestamps.t.sol | 4 - test/integration/shared/lockup/Lockup.t.sol | 11 +- test/invariant/Invariant.t.sol | 12 - test/invariant/Lockup.t.sol | 5 +- test/invariant/LockupDynamic.t.sol | 1 - test/invariant/LockupTranched.t.sol | 1 - .../invariant/handlers/ComptrollerHandler.sol | 50 - .../handlers/LockupDynamicCreateHandler.sol | 14 +- test/invariant/handlers/LockupHandler.sol | 16 - .../handlers/LockupLinearCreateHandler.sol | 4 +- .../handlers/LockupTranchedCreateHandler.sol | 14 +- .../concrete/comptroller/Comptroller.t.sol | 23 - .../concrete/comptroller/constructor.t.sol | 22 - test/utils/Calculations.sol | 16 +- test/utils/Constants.sol | 2 +- test/utils/Defaults.sol | 12 +- test/utils/DeployOptimized.sol | 28 +- test/utils/Events.sol | 18 - test/utils/Fuzzers.sol | 64 +- test/utils/Precompiles.sol | 88 +- test/utils/Precompiles.t.sol | 28 +- 106 files changed, 942 insertions(+), 2400 deletions(-) delete mode 100644 script/DeployComptroller.s.sol delete mode 100644 script/DeployDeterministicComptroller.s.sol delete mode 100644 src/SablierV2Comptroller.sol delete mode 100644 src/abstracts/SablierV2Base.sol delete mode 100644 src/interfaces/ISablierV2Base.sol delete mode 100644 src/interfaces/ISablierV2Comptroller.sol delete mode 100644 test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol delete mode 100644 test/integration/concrete/comptroller/protocol-fees/protocolFees.tree delete mode 100644 test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol delete mode 100644 test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree delete mode 100644 test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol delete mode 100644 test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.tree delete mode 100644 test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol delete mode 100644 test/integration/concrete/lockup/protocol-revenues/protocolRevenues.tree delete mode 100644 test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol delete mode 100644 test/integration/concrete/lockup/set-comptroller/setComptroller.tree delete mode 100644 test/integration/fuzz/comptroller/setProtocolFee.t.sol delete mode 100644 test/invariant/handlers/ComptrollerHandler.sol delete mode 100644 test/unit/concrete/comptroller/Comptroller.t.sol delete mode 100644 test/unit/concrete/comptroller/constructor.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index 36efba67a..78dea1dae 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,399 +1,588 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87467) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78051) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78060) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79265) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11325) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90245) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14289) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19502) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19583) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87747) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78320) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78329) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79516) -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: 19488) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19569) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 832905) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6271) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32323) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 858977) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12362) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78511) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 341083) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 945392) -CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1193272, ~: 1199808) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565330) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6294) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32471) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 572337) -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: 245284) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 656826) -CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 796137, ~: 797068) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 386034) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 371186) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97125) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 373377) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 371753) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76356) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11321) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87331) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 67953) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26999) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 261387) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 453460, ~: 454703) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76876, ~: 77083) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269407) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254535) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 77545) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 256715) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 255102) -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: 68215) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 27107) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 185551) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 310087, ~: 309980) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 77030, ~: 77168) -ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319605) -ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18907) -ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 246382) -ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18915) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5375705) -Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 4181201) -CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380468) -CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4093934, ~: 3551084) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287497) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286429, ~: 286529) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 370814) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 377602) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 47460) -CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 57967) -CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3960440, ~: 3983787) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282850) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289617) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41034) -CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 51617) -CreateWithRange_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithRange(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256)),uint256) (runs: 50, μ: 368550, ~: 383704) -GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13215) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307626) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12049) -GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 234371) -GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12035) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 234855) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11392) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 310423) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11682) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 237142) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11678) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 310198) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11538) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 236971) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11546) -GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 309669) -GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13125) -GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 237189) -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: 72359) -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: 72628) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 10993) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 362569) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 332532) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 337717) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 337776) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 377296) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 399025) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 287602) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 257289) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 262474) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 262533) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 298835) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 320596) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 315125) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13758) -GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 307344) -GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11814) -GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 234105) -GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11816) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 310550) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11823) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 237317) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11831) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 278587) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52001) -GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15544) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 34942) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 39430) -GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14299) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 384549) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 335769) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387484, ~: 388043) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337464, ~: 337671) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282044) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262526) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285208, ~: 285164) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 264276, ~: 264428) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 515599) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 335947) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 327214) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11239) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 372587) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 262856) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 254006) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11263) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 376050) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 362248) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 330471) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 336218) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 352545) -IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11525) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 297640) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 287339) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 257286) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 263145) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 263725) -IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361686) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326638) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 286739) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 253415) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11212) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 326978) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8527) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 253777) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8570) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 327140) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11674) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 515598) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 253961) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11739) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 372642) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 375588) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 361762) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 329908) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 335829) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 352030) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11085) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 297147) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 286815) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 256685) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 262728) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 263172) -IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11106) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 16961) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16735) -MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 1039755) -ProtocolFees_Integration_Concrete_Test:test_ProtocolFees() (gas: 41122) -ProtocolFees_Integration_Concrete_Test:test_ProtocolFees_ProtocolFeeNotSet() (gas: 9869) -ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 320117) -ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10125) -ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246871) -ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10111) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361690) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 335675) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 335645) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 342492) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375464) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 398523) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523192) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11066) -RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 48183, ~: 63495) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 286739) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 262439) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 262539) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 264026) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297019) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 320110) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 380185) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11077) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30877, ~: 30917) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 693967) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 687042) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 292407) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 692171) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 687649) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11567) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87318) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68257) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24669) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 649447) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 481265) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 474308) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 219253) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 479445) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 474915) -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: 68541) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24799) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 436637) -SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 12117) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89934) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80731) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80762) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 81871) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11317) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90162) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14278) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19536) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19551) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 92131) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82942) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82973) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 84085) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11293) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 82872) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14254) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19512) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19527) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100990) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91801) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91832) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 92960) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11337) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89982) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14298) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19556) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19571) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 815232) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6329) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32142) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 835114) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12417) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78395) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326410) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 918387) +CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 1175383, ~: 1174865) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 595097) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6332) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34306) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 636392) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12414) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80403) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254607) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 719687) +CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 861197, ~: 863450) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 770735) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6354) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41696) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934828) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12436) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87796) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343455) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028867) +CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 1175542, ~: 1173622) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 371699) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 356833) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97011) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 358721) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357400) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 71443) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11314) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86956) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63201) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26741) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246730) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 440408, ~: 440715) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 71792, ~: 71598) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 276919) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262068) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 79360) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 263946) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 262635) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 73435) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11298) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79680) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65441) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 28901) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192902) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 317991, ~: 318255) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 73922, ~: 73871) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 360534) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 345630) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 86746) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 347552) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346197) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 80881) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11342) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86790) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74272) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36313) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273818) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 404148, ~: 404572) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 81368, ~: 81317) +Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5026066) +Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3890433) +Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4081319) +CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 345377) +CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 5, μ: 5491601, ~: 7294034) +CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 273812) +CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 5, μ: 272460, ~: 272184) +CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 375613) +CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 5, μ: 5587007, ~: 6183306) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 338393) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 344814) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 38819) +CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 5, μ: 3746257, ~: 3891426) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 272572) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 279015) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_CliffTimeZero() (gas: 228453) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 33005) +CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 5, μ: 358201, ~: 362647) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 365732) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 372087) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41674) +CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 5, μ: 3607120, ~: 3725226) +GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13242) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 276169) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) +GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 224871) +GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11969) +GetAsset_LockupTranched_Integration_Concrete_Test:test_GetAsset() (gas: 301708) +GetAsset_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 225459) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11436) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 279054) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11668) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 227708) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11634) +GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 304615) +GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11690) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 278874) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 227598) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 304457) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11612) +GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 278255) +GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13067) +GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 227888) +GetRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13251) +GetRange_LockupTranched_Integration_Concrete_Test:test_GetRange() (gas: 303751) +GetRange_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13067) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 12464) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67739) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11456) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 12436) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69950) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11428) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 12464) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78809) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11456) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 311270) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 301075) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 306305) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306298) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 345790) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 347632) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 258243) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 247789) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 253019) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253012) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289238) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 290999) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11932) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 339855) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 326614) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 331844) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 331837) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369129) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 370938) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283695) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13744) +GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 275931) +GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11800) +GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 224627) +GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11772) +GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 301470) +GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11800) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 279116) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 227818) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11765) +GetStartTime_LockupTranched_Integration_Concrete_Test:test_GetStartTime() (gas: 304655) +GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 264782) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52545) +GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15581) +GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 37598) +GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 42180) +GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14337) +GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream() (gas: 291442) +GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 57205) +GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15565) +GetTranches_LockupTranched_Integration_Concrete_Test:test_GetTranches() (gas: 310185) +GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13497) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 355530) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304291) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 358827, ~: 359251) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 305919, ~: 305643) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 274898) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253005) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11932) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 278393, ~: 278657) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 254633, ~: 254357) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356428) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 329830) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 359942, ~: 360187) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 331320, ~: 331182) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 481194) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 304629) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 295851) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11269) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 382141) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 253537) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 244594) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11285) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable() (gas: 530457) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 331729) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 321418) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11294) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 344613) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311043) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299108) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 304895) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 321223) +IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11552) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288108) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258068) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 247874) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 253826) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 254340) +IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11590) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 367998) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 339679) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 324698) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332018) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 332495) +IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11599) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 310426) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 295220) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11181) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 257422) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 243957) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11194) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted() (gas: 339033) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 320781) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11203) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 295557) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8510) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 244299) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8526) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 321101) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 8513) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 295700) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11642) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 481113) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 244459) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11677) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 382091) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 321261) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11664) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 530370) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344120) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 310524) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 298512) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 304478) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 320675) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11090) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 287615) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 257544) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 247273) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 253409) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 253787) +IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11128) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 367461) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 339111) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 324053) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 331557) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 331898) +IsWarm_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11093) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 17279) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16907) +MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 911419) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 310510) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304381) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 304352) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311251) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344054) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347259) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 488812) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11129) +RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 44041, ~: 30163) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 257501) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253088) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 253253) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 254718) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 287520) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 290644) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 389772) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) +RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 32677, ~: 32471) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 339091) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331273) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 331424) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 332554) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367389) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 370561) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538043) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) +RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 41154, ~: 40603) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 673760) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 666877) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 278302) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672112) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 667440) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11618) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87301) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63570) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24775) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 629158) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 526920) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520007) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 227020) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525172) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 520570) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 80032) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65826) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26936) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 482308) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 749480) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 742567) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 306605) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749114) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743130) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87098) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74613) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34304) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 703431) +SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 12029) 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() (gas: 18460) 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: 625096) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 546503) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 12399) -SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 214569) -SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23283) -SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 214566) -SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23280) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6551561) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2301931) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6550746) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2300992) -SetProtocolFee_Integration_Fuzz_Test:testFuzz_SetProtocolFee(uint256) (runs: 50, μ: 42999, ~: 42942) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11651) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 352645) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 362387) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 336430) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 330552) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 376224) -StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11681) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 263201) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 287454) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 263343) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 257343) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 297797) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11319) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestone1st() (gas: 45903) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestoneNot1st() (gas: 50746) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 256802) -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: 68591) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20360) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26601) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87753) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116291) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3517521, ~: 3128319) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3967659, ~: 4100727) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 274652, ~: 268659) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11316) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 26225) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 17291) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 27110) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68821) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20272) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26632) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 78511) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 107015) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 232606, ~: 233276) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 27328, ~: 27604) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 237475, ~: 239593) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13542) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6618523) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2304797) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6618805) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2304889) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6628035) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2314332) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11634) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 321307) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311132) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305062) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299139) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 344739) +StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11637) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 253708) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258117) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 253958) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 247865) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288199) +StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11659) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf() (gas: 331933) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 339741) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332163) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 324702) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368102) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11349) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46012) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 50875) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 242637) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20263) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 25627) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 63926) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20393) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26723) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87670) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111421) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 5, μ: 2511998, ~: 2840809) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 5, μ: 3710255, ~: 3160094) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 5, μ: 259274, ~: 259452) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 28307) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 19297) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29169) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66161) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 22311) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 28824) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 80402) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104039) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 5, μ: 240765, ~: 239992) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 5, μ: 29242, ~: 28966) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 5, μ: 246655, ~: 248105) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 43891) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35099) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 29618) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 34982) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 74969) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 29725) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36258) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87534) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111207) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 5, μ: 2959814, ~: 3379078) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 5, μ: 2997213, ~: 2909950) +TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13902) 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_RevertGiven_NFTDoesNotExist() (gas: 13877) 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: 314077) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 326383) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 240264) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 253108) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12048) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 364341) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 327528) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12069) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 289132) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 254305) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75278) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14165) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 264926) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 158530) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100422) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 137956, ~: 155649) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75560) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14179) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189194) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 111600) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100752) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 99586, ~: 109924) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 135018) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80155) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117353, ~: 120534) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82847, ~: 82960) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 74513) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80471) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 73547, ~: 73702) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83094, ~: 83276) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73732) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21033) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124565) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83205) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1829631) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9112) -WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2743359, ~: 2743632) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73995) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21020) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 105152) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83468) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1263428) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9165) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1772371, ~: 1772218) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19930) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67734) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 384964) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112727) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81286) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72499) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 362639) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122641) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 389972) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 363194) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 382151) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 125250, ~: 98709) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145442, ~: 145442) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3959980, ~: 3999315) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160679, ~: 160866) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19917) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67997) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 268321) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 93114) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 61662) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72696) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 259620) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 75768) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 273356) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 260175) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 292784) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 99363, ~: 99269) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 112233, ~: 112233) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 141175, ~: 141030) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12045) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 377995) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 347520) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 337125) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 363517) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 333874) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 340074) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 378359) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 400382) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 334198, ~: 351909) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 296030, ~: 289610) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12043) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 253526) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 263386) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 288514) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 258565) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 264895) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 299907) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 321862) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 286937) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 461607, ~: 462240) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263604, ~: 263867) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 437554, ~: 438494) \ No newline at end of file +TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13899) +TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) +TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6601) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 281816) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294142) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 230015) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 242845) +TransferFrom_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 307514) +TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 319688) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11972) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 312812) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 296044) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11985) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 259524) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 244781) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11972) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 339741) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 321583) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72520) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14131) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 250166) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 160470) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97615) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 138955, ~: 157016) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74730) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14116) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196381) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 115324) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99898) +WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 105715, ~: 113052) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83583) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14138) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277260) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 125432) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108707) +WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 108104, ~: 123265) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 137497) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 77911) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 117056, ~: 123442) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 80372, ~: 80265) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 78765) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80135) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 77716, ~: 77609) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 82596, ~: 82489) +WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax() (gas: 90206) +WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 89003) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 87584, ~: 88106) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 91464, ~: 91357) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73532) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20750) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124808) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83005) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 268527) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6576) +WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 2695106, ~: 2695379) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 75674) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20636) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 109270) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 85147) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 221649) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6549) +WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 1986261, ~: 1986387) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 84532) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20707) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124109) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 94005) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 245406) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6593) +WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 2876750, ~: 2876876) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19879) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 65314) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 354742) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113106) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 83569) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 84520) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 67797) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297401) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 354175) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 107941) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 375539) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 354751) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 322132) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297364) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 296886) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85185) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 127476) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 126442, ~: 100726) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 147886, ~: 147886) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 5, μ: 3809541, ~: 4704372) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 160725, ~: 160792) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 105849, ~: 105849) +Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19848) +Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67539) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 273616) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 95396) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 65873) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 66824) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 69934) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 229906) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 273047) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 76596) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 280732) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 273623) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 240955) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 229870) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229392) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 67489) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 109726) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 104108, ~: 104278) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 116531, ~: 116531) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 142788, ~: 142836) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 74502, ~: 74502) +Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19855) +Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 76333) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 355808) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 102748) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73225) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74176) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 77360) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 310741) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355239) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 85301) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 364263) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355815) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323117) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 310705) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310227) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 74841) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 117182) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 115236, ~: 114843) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 125232, ~: 125232) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 150199, ~: 150351) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 5, μ: 3284018, ~: 3684660) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 83209, ~: 83209) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11987) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 346640) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316158) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 305667) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 312216) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 302415) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 308704) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 346784) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 348964) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 5, μ: 317851, ~: 302058) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 5, μ: 290517, ~: 288578) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12010) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 244010) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 253946) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 259188) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 249082) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 255565) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290276) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292308) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277445) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 5, μ: 462713, ~: 461869) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 5, μ: 253983, ~: 253707) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 5, μ: 439185, ~: 440083) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11987) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364161) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 337855) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 332563) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 340800) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 329311) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 335780) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370122) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372269) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 5, μ: 328843, ~: 328727) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 5, μ: 303871, ~: 303913) \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index e93261086..7dc72bba3 100644 --- a/foundry.toml +++ b/foundry.toml @@ -5,7 +5,6 @@ ffi = true fs_permissions = [{ access = "read", path = "out-optimized" }] gas_reports = [ - "SablierV2Comptroller", "SablierV2LockupDynamic", "SablierV2LockupLinear", "SablierV2LockupTranched", diff --git a/script/DeployComptroller.s.sol b/script/DeployComptroller.s.sol deleted file mode 100644 index 06aa513bd..000000000 --- a/script/DeployComptroller.s.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; - -import { BaseScript } from "./Base.s.sol"; - -contract DeployComptroller is BaseScript { - function run(address initialAdmin) public virtual broadcast returns (SablierV2Comptroller comptroller) { - comptroller = new SablierV2Comptroller(initialAdmin); - } -} diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index 8ab569184..c7635ab7f 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -11,28 +10,25 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys all V2 Core contract in the following order: /// -/// 1. {SablierV2Comptroller} -/// 2. {SablierV2NFTDescriptor} -/// 3. {SablierV2LockupDynamic} -/// 4. {SablierV2LockupLinear} -/// 5. {SablierV2LockupTranched} +/// 1. {SablierV2NFTDescriptor} +/// 2. {SablierV2LockupDynamic} +/// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} contract DeployCore is BaseScript { function run(address initialAdmin) public virtual broadcast returns ( - SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) { - comptroller = new SablierV2Comptroller(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 16e10359a..9e400dbb7 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -11,10 +10,9 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys these contracts in the following order: /// -/// 1. {SablierV2Comptroller} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} +/// 1. {SablierV2LockupDynamic} +/// 2. {SablierV2LockupLinear} +/// 3. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { function run( address initialAdmin, @@ -24,15 +22,13 @@ contract DeployCore2 is BaseScript { virtual broadcast returns ( - SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) { - comptroller = new SablierV2Comptroller(initialAdmin); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol index 2702b29dc..61a149b59 100644 --- a/script/DeployCore3.s.sol +++ b/script/DeployCore3.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -16,10 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 3. {SablierV2LockupLinear} /// 4. {SablierV2LockupTranched} contract DeployCore3 is BaseScript { - function run( - address initialAdmin, - ISablierV2Comptroller comptroller - ) + function run(address initialAdmin) public virtual broadcast @@ -31,8 +27,8 @@ contract DeployCore3 is BaseScript { ) { nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicComptroller.s.sol b/script/DeployDeterministicComptroller.s.sol deleted file mode 100644 index aa46db9f0..000000000 --- a/script/DeployDeterministicComptroller.s.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @notice Deploys {SablierV2Comptroller} at a deterministic address across chains. -/// @dev Reverts if the contract has already been deployed. -contract DeployDeterministicComptroller is BaseScript { - function run(address initialAdmin) public virtual broadcast returns (SablierV2Comptroller comptroller) { - bytes32 salt = constructCreate2Salt(); - comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); - } -} diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 1e5a6a9da..bde134d9b 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -11,11 +10,10 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys all V2 Core contracts at deterministic addresses across chains, in the following order: /// -/// 1. {SablierV2Comptroller} -/// 2. {SablierV2NFTDescriptor} -/// 3. {SablierV2LockupDynamic} -/// 4. {SablierV2LockupLinear} -/// 5. {SablierV2LockupTranched} +/// 1. {SablierV2NFTDescriptor} +/// 2. {SablierV2LockupDynamic} +/// 3. {SablierV2LockupLinear} +/// 4. {SablierV2LockupTranched} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { @@ -24,7 +22,6 @@ contract DeployDeterministicCore is BaseScript { virtual broadcast returns ( - SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched, @@ -32,10 +29,9 @@ contract DeployDeterministicCore is BaseScript { ) { bytes32 salt = constructCreate2Salt(); - comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 86d41ea84..d86bda48e 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -11,10 +10,9 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys these contracts at deterministic addresses across chains, in the following order: /// -/// 1. {SablierV2Comptroller} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} +/// 1. {SablierV2LockupDynamic} +/// 2. {SablierV2LockupLinear} +/// 3. {SablierV2LockupTranched} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { @@ -26,16 +24,14 @@ contract DeployDeterministicCore2 is BaseScript { virtual broadcast returns ( - SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) { bytes32 salt = constructCreate2Salt(); - comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol index 30b7e49ca..2ba0a06a5 100644 --- a/script/DeployDeterministicCore3.s.sol +++ b/script/DeployDeterministicCore3.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -18,10 +17,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore3 is BaseScript { - function run( - address initialAdmin, - ISablierV2Comptroller comptroller - ) + function run(address initialAdmin) public virtual broadcast @@ -34,8 +30,8 @@ contract DeployDeterministicCore3 is BaseScript { { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); } } diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index b0cdce438..68a85d56c 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; @@ -12,7 +11,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployDeterministicLockupDynamic is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -21,7 +19,6 @@ contract DeployDeterministicLockupDynamic is BaseScript { returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); } } diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index 188fc6d7e..de36726ab 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; @@ -12,7 +11,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployDeterministicLockupLinear is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -21,6 +19,6 @@ contract DeployDeterministicLockupLinear is BaseScript { returns (SablierV2LockupLinear lockupLinear) { bytes32 salt = constructCreate2Salt(); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor); } } diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index 9cb8d5c36..b52807539 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -12,7 +11,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployDeterministicLockupTranched is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -21,7 +19,6 @@ contract DeployDeterministicLockupTranched is BaseScript { returns (SablierV2LockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); - lockupTranched = - new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); } } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index e42c7ebde..e99c78b2f 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; @@ -10,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupDynamic is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -18,6 +16,6 @@ contract DeployLockupDynamic is BaseScript { broadcast returns (SablierV2LockupDynamic lockupDynamic) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxCount); } } diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index a53ced857..940966a2f 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; @@ -10,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupLinear is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -18,6 +16,6 @@ contract DeployLockupLinear is BaseScript { broadcast returns (SablierV2LockupLinear lockupLinear) { - lockupLinear = new SablierV2LockupLinear(initialAdmin, initialComptroller, initialNFTDescriptor); + lockupLinear = new SablierV2LockupLinear(initialAdmin, initialNFTDescriptor); } } diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 09a718dc2..2dc6d8845 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -10,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupTranched is BaseScript { function run( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) public @@ -18,6 +16,6 @@ contract DeployLockupTranched is BaseScript { broadcast returns (SablierV2LockupTranched lockupTranched) { - lockupTranched = new SablierV2LockupTranched(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxCount); } } diff --git a/script/Init.s.sol b/script/Init.s.sol index 9d917df43..a944d4a94 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -17,7 +17,7 @@ interface IERC20Mint { function mint(address beneficiary, uint256 value) external; } -/// @notice Initializes the protocol by setting up the comptroller and creating some streams. +/// @notice Initializes the protocol by creating some streams. contract Init is BaseScript { function run( ISablierV2LockupLinear lockupLinear, diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index e0cfd8a4a..bd3e9123b 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -60,19 +60,6 @@ deployments=./deployments rm -rf ${deployments} mkdir ${deployments} -# Addresses taken from https://docs.sablier.com/contracts/v2/deployments -ARBITRUM_COMPTROLLER="0x17Ec73692F0aDf7E7C554822FBEAACB4BE781762" -ARBITRUM_SEPOLIA_COMPTROLLER="0xA6A0cfA3442053fbB516D55205A749Ef2D33aed9" -AVALANCHE_COMPTROLLER="0x66F5431B0765D984f82A4fc4551b2c9ccF7eAC9C" -BASE_COMPTROLLER="0x7Faaedd40B1385C118cA7432952D9DC6b5CbC49e" -BSC_COMPTROLLER="0x33511f69A784Fd958E6713aCaC7c9dCF1A5578E8" -GNOSIS_COMPTROLLER="0x73962c44c0fB4cC5e4545FB91732a5c5e87F55C2" -MAINNET_COMPTROLLER="0xC3Be6BffAeab7B297c03383B4254aa3Af2b9a5BA" -OPTIMISM_COMPTROLLER="0x1EECb6e6EaE6a1eD1CCB4323F3a146A7C5443A10" -POLYGON_COMPTROLLER="0x9761692EDf10F5F2A69f0150e2fd50dcecf05F2E" -SCROLL_COMPTROLLER="0x859708495E3B3c61Bbe19e6E3E1F41dE3A5C5C5b" -SEPOLIA_COMPTROLLER="0x2006d43E65e66C5FF20254836E63947FA8bAaD68" - # Addresses taken from https://docs.sablier.com/concepts/governance export ARBITRUM_ADMIN="0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376" export ARBITRUM_SEPOLIA_ADMIN="0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F" @@ -116,17 +103,17 @@ declare -A chains # define function to initialize all configurations function initialize { - chains["arbitrum"]="$ARBITRUM_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_ADMIN $ARBITRUM_COMPTROLLER" - chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_ADMIN $ARBITRUM_SEPOLIA_COMPTROLLER" - chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_ADMIN $AVALANCHE_COMPTROLLER" - chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_ADMIN $BASE_COMPTROLLER" - chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_ADMIN $BSC_COMPTROLLER" - chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_ADMIN $GNOSIS_COMPTROLLER" - chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_ADMIN $MAINNET_COMPTROLLER" - chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_ADMIN $OPTIMISM_COMPTROLLER" - chains["polygon"]="$POLYGON_RPC_URL $POLYGONSCAN_API_KEY $POLYGON_ADMIN $POLYGON_COMPTROLLER" - chains["sepolia"]="$SEPOLIA_RPC_URL $ETHERSCAN_API_KEY $SEPOLIA_ADMIN $SEPOLIA_COMPTROLLER" - chains["scroll"]="$SCROLL_RPC_URL $SCROLLSCAN_API_KEY $SCROLL_ADMIN $SCROLL_COMPTROLLER" + chains["arbitrum"]="$ARBITRUM_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_ADMIN" + chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_ADMIN" + chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_ADMIN" + chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_ADMIN" + chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_ADMIN" + chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_ADMIN" + chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_ADMIN" + chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_ADMIN" + chains["polygon"]="$POLYGON_RPC_URL $POLYGONSCAN_API_KEY $POLYGON_ADMIN" + chains["sepolia"]="$SEPOLIA_RPC_URL $ETHERSCAN_API_KEY $SEPOLIA_ADMIN" + chains["scroll"]="$SCROLL_RPC_URL $SCROLLSCAN_API_KEY $SCROLL_ADMIN" } # define function to initialize limited configurations @@ -137,19 +124,6 @@ function initialize_interactive { echo -e "2. Enter Etherscan API key: \c" read api_key - - # Comptroller only - chains["arbitrum"]="$ARBITRUM_COMPTROLLER" - chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_COMPTROLLER" - chains["avalanche"]="$AVALANCHE_COMPTROLLER" - chains["base"]="$BASE_COMPTROLLER" - chains["bnb_smart_chain"]="$BSC_COMPTROLLER" - chains["gnosis"]="$GNOSIS_COMPTROLLER" - chains["mainnet"]="$MAINNET_COMPTROLLER" - chains["optimism"]="$OPTIMISM_COMPTROLLER" - chains["polygon"]="$POLYGON_COMPTROLLER" - chains["sepolia"]="$SEPOLIA_COMPTROLLER" - chains["scroll"]="$SCROLL_COMPTROLLER" } if [ -f .env.deployment ]; then @@ -165,7 +139,7 @@ else # load values from the terminal prompt echo -e "${WC}Missing '.env.deployment'. Provide details below: ${NC}\n" - # initialize chains with comptroller + # initialize chains initialize_interactive fi @@ -204,7 +178,7 @@ for ((i=1; i<=$#; i++)); do # Print the supported chains for chain in "${sorted_names[@]}"; do - IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}" + IFS=' ' read -r rpc_url api_key admin <<< "${chains[$chain]}" # Print the chain printf "%-20s %-20s\n" "${chain}" @@ -217,7 +191,6 @@ for ((i=1; i<=$#; i++)); do INTERACTIVE=true echo -e "Interactive mode activated. Provide details below: \n" - # initialize only comptroller initialize_interactive fi @@ -301,12 +274,9 @@ for chain in "${provided_chains[@]}"; do # load values from the terminal prompt echo -e "Enter RPC URL for ${chain}: \c" read rpc_url - - # Get the values from the chains array - IFS=' ' read -r comptroller <<< "${chains[$chain]}" else - # Split the configuration into RPC, API key, admin, and comptroller - IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}" + # Split the configuration into RPC, API key, and admin + IFS=' ' read -r rpc_url api_key admin <<< "${chains[$chain]}" fi # Declare the deployment command @@ -330,9 +300,9 @@ for chain in "${provided_chains[@]}"; do # echo removes single quotes #################################################################### if [[ ${READ_ONLY} == true ]]; then - deployment_command+=("--sig" "'run(address,address)'") + deployment_command+=("--sig" "'run(address)'") else - deployment_command+=("--sig" "run(address,address)") + deployment_command+=("--sig" "run(address)") fi else # Construct the command @@ -344,14 +314,13 @@ for chain in "${provided_chains[@]}"; do deployment_command+=("--rpc-url" "${rpc_url}") if [[ ${READ_ONLY} == true ]]; then - deployment_command+=("--sig" "'run(address,address)'") + deployment_command+=("--sig" "'run(address)'") else - deployment_command+=("--sig" "run(address,address)") + deployment_command+=("--sig" "run(address)") fi fi deployment_command+=("${admin}") - deployment_command+=("${comptroller}") deployment_command+=("-vvv") # Append additional options if gas price is enabled diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index 0d9d6a331..ca30ca1c0 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -23,15 +23,12 @@ mkdir $artifacts \ FOUNDRY_PROFILE=optimized forge build # Copy the production artifacts -cp out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json $artifacts cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $artifacts cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $artifacts cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $artifacts cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $artifacts interfaces=./artifacts/interfaces -cp out-optimized/ISablierV2Base.sol/ISablierV2Base.json $interfaces -cp out-optimized/ISablierV2Comptroller.sol/ISablierV2Comptroller.json $interfaces cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $interfaces cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $interfaces cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $interfaces diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index cb0d51361..9a69e33fb 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -12,7 +12,6 @@ set -euo pipefail FOUNDRY_PROFILE=optimized forge build # Retrieve the raw bytecodes, removing the "0x" prefix -comptroller=$(cat out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json | jq -r '.bytecode.object' | cut -c 3-) lockup_dynamic=$(cat out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) @@ -25,7 +24,6 @@ if [ ! -f $precompiles_path ]; then fi # Replace the current bytecodes -sd "(BYTECODE_COMPTROLLER =)[^;]+;" "\$1 hex\"$comptroller\";" $precompiles_path sd "(BYTECODE_LOCKUP_DYNAMIC =)[^;]+;" "\$1 hex\"$lockup_dynamic\";" $precompiles_path sd "(BYTECODE_LOCKUP_LINEAR =)[^;]+;" "\$1 hex\"$lockup_linear\";" $precompiles_path sd "(BYTECODE_LOCKUP_TRANCHED =)[^;]+;" "\$1 hex\"$lockup_tranched\";" $precompiles_path diff --git a/src/SablierV2Comptroller.sol b/src/SablierV2Comptroller.sol deleted file mode 100644 index a1ba22632..000000000 --- a/src/SablierV2Comptroller.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.22; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { Adminable } from "./abstracts/Adminable.sol"; -import { IAdminable } from "./interfaces/IAdminable.sol"; -import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; - -/* - -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ - - ██████╗ ██████╗ ███╗ ███╗██████╗ ████████╗██████╗ ██████╗ ██╗ ██╗ ███████╗██████╗ -██╔════╝██╔═══██╗████╗ ████║██╔══██╗╚══██╔══╝██╔══██╗██╔═══██╗██║ ██║ ██╔════╝██╔══██╗ -██║ ██║ ██║██╔████╔██║██████╔╝ ██║ ██████╔╝██║ ██║██║ ██║ █████╗ ██████╔╝ -██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║ ██╔══██╗██║ ██║██║ ██║ ██╔══╝ ██╔══██╗ -╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║╚██████╔╝███████╗███████╗███████╗██║ ██║ - ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ - -*/ - -/// @title SablierV2Comptroller -/// @notice See the documentation in {ISablierV2Comptroller}. -contract SablierV2Comptroller is - ISablierV2Comptroller, // 1 inherited component - Adminable // 1 inherited component -{ - /*////////////////////////////////////////////////////////////////////////// - STATE VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - - /// @inheritdoc ISablierV2Comptroller - mapping(IERC20 asset => UD60x18 fee) public override protocolFees; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Emits a {TransferAdmin} event. - /// @param initialAdmin The address of the initial contract admin. - constructor(address initialAdmin) { - admin = initialAdmin; - emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); - } - - /*////////////////////////////////////////////////////////////////////////// - USER-FACING NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @inheritdoc ISablierV2Comptroller - function setProtocolFee(IERC20 asset, UD60x18 newProtocolFee) external override onlyAdmin { - // Effects: set the new global fee. - UD60x18 oldProtocolFee = protocolFees[asset]; - protocolFees[asset] = newProtocolFee; - - // Log the change of the protocol fee. - emit ISablierV2Comptroller.SetProtocolFee({ - admin: msg.sender, - asset: asset, - oldProtocolFee: oldProtocolFee, - newProtocolFee: newProtocolFee - }); - } -} diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index c4da4761d..21d45b6ae 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -7,10 +7,8 @@ import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uint40.sol"; import { SD59x18 } from "@prb/math/src/SD59x18.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "./interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; import { Helpers } from "./libraries/Helpers.sol"; @@ -37,7 +35,7 @@ import { Lockup, LockupDynamic } from "./types/DataTypes.sol"; /// @title SablierV2LockupDynamic /// @notice See the documentation in {ISablierV2LockupDynamic}. contract SablierV2LockupDynamic is - ISablierV2LockupDynamic, // 6 inherited components + ISablierV2LockupDynamic, // 5 inherited components SablierV2Lockup // 14 inherited components { using CastingUint128 for uint128; @@ -60,17 +58,15 @@ contract SablierV2LockupDynamic is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. - /// @param initialComptroller The address of the initial comptroller. /// @param initialNFTDescriptor The address of the NFT descriptor contract. /// @param maxSegmentCount The maximum number of segments allowed in a stream. constructor( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor, uint256 maxSegmentCount ) ERC721("Sablier V2 Lockup Dynamic NFT", "SAB-V2-LOCKUP-DYN") - SablierV2Lockup(initialAdmin, initialComptroller, initialNFTDescriptor) + SablierV2Lockup(initialAdmin, initialNFTDescriptor) { MAX_SEGMENT_COUNT = maxSegmentCount; nextStreamId = 1; @@ -317,13 +313,9 @@ contract SablierV2LockupDynamic is internal returns (uint256 streamId) { - // Safe Interactions: query the protocol fee. This is safe because it's a known Sablier contract that does - // not call other unknown contracts. - UD60x18 protocolFee = comptroller.protocolFees(params.asset); - - // Checks: check the fees and calculate the fee amounts. + // Checks: check the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = - Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); + Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); // Checks: validate the user-provided parameters. Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.segments, MAX_SEGMENT_COUNT, params.startTime); @@ -352,24 +344,16 @@ contract SablierV2LockupDynamic is _segments[streamId].push(params.segments[i]); } - // Effects: bump the next stream id and record the protocol fee. + // Effects: bump the next stream id. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. nextStreamId = streamId + 1; - protocolRevenues[params.asset] = protocolRevenues[params.asset] + createAmounts.protocolFee; } // Effects: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit and the protocol fee. - // Using unchecked arithmetic because the deposit and the protocol fee are bounded by the total amount. - unchecked { - params.asset.safeTransferFrom({ - from: msg.sender, - to: address(this), - value: createAmounts.deposit + createAmounts.protocolFee - }); - } + // Interactions: transfer the deposit amount. + params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); // Interactions: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index fff01f8e0..a88ac2b4d 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -8,7 +8,6 @@ import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupLinear } from "./interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; import { Helpers } from "./libraries/Helpers.sol"; @@ -35,7 +34,7 @@ import { Lockup, LockupLinear } from "./types/DataTypes.sol"; /// @title SablierV2LockupLinear /// @notice See the documentation in {ISablierV2LockupLinear}. contract SablierV2LockupLinear is - ISablierV2LockupLinear, // 6 inherited components + ISablierV2LockupLinear, // 5 inherited components SablierV2Lockup // 14 inherited components { using SafeERC20 for IERC20; @@ -53,15 +52,13 @@ contract SablierV2LockupLinear is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. - /// @param initialComptroller The address of the initial comptroller. /// @param initialNFTDescriptor The address of the initial NFT descriptor. constructor( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor ) ERC721("Sablier V2 Lockup Linear NFT", "SAB-V2-LOCKUP-LIN") - SablierV2Lockup(initialAdmin, initialComptroller, initialNFTDescriptor) + SablierV2Lockup(initialAdmin, initialNFTDescriptor) { nextStreamId = 1; } @@ -236,13 +233,9 @@ contract SablierV2LockupLinear is internal returns (uint256 streamId) { - // Safe Interactions: query the protocol fee. This is safe because it's a known Sablier contract that does - // not call other unknown contracts. - UD60x18 protocolFee = comptroller.protocolFees(params.asset); - - // Checks: check the fees and calculate the fee amounts. + // Checks: check the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = - Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); + Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); // Checks: validate the user-provided parameters. Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.range); @@ -269,25 +262,17 @@ contract SablierV2LockupLinear is _cliffs[streamId] = params.range.cliff; } - // Effects: bump the next stream id and record the protocol fee. + // Effects: bump the next stream id. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. unchecked { nextStreamId = streamId + 1; - protocolRevenues[params.asset] = protocolRevenues[params.asset] + createAmounts.protocolFee; } // Effects: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit and the protocol fee. - // Using unchecked arithmetic because the deposit and the protocol fee are bounded by the total amount. - unchecked { - params.asset.safeTransferFrom({ - from: msg.sender, - to: address(this), - value: createAmounts.deposit + createAmounts.protocolFee - }); - } + // Interactions: transfer the deposit amount. + params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); // Interactions: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index dae58989d..fae72f6bb 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -4,10 +4,8 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupTranched } from "./interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; import { Helpers } from "./libraries/Helpers.sol"; @@ -34,7 +32,7 @@ import { Lockup, LockupTranched } from "./types/DataTypes.sol"; /// @title SablierV2LockupTranched /// @notice See the documentation in {ISablierV2LockupTranched}. contract SablierV2LockupTranched is - ISablierV2LockupTranched, // 6 inherited components + ISablierV2LockupTranched, // 5 inherited components SablierV2Lockup // 14 inherited components { using SafeERC20 for IERC20; @@ -55,17 +53,15 @@ contract SablierV2LockupTranched is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. - /// @param initialComptroller The address of the initial comptroller. /// @param initialNFTDescriptor The address of the NFT descriptor contract. /// @param maxTrancheCount The maximum number of tranches allowed in a stream. constructor( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor initialNFTDescriptor, uint256 maxTrancheCount ) ERC721("Sablier V2 Lockup Tranched NFT", "SAB-V2-LOCKUP-TRA") - SablierV2Lockup(initialAdmin, initialComptroller, initialNFTDescriptor) + SablierV2Lockup(initialAdmin, initialNFTDescriptor) { MAX_TRANCHE_COUNT = maxTrancheCount; nextStreamId = 1; @@ -226,13 +222,9 @@ contract SablierV2LockupTranched is internal returns (uint256 streamId) { - // Safe Interactions: query the protocol fee. This is safe because it's a known Sablier contract that does - // not call other unknown contracts. - UD60x18 protocolFee = comptroller.protocolFees(params.asset); - - // Checks: check the fees and calculate the fee amounts. + // Checks: check the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = - Helpers.checkAndCalculateFees(params.totalAmount, protocolFee, params.broker.fee, MAX_FEE); + Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); // Checks: validate the user-provided parameters. Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.tranches, MAX_TRANCHE_COUNT, params.startTime); @@ -261,24 +253,16 @@ contract SablierV2LockupTranched is _tranches[streamId].push(params.tranches[i]); } - // Effects: bump the next stream id and record the protocol fee. + // Effects: bump the next stream id. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. nextStreamId = streamId + 1; - protocolRevenues[params.asset] = protocolRevenues[params.asset] + createAmounts.protocolFee; } // Effects: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit and the protocol fee. - // Using unchecked arithmetic because the deposit and the protocol fee are bounded by the total amount. - unchecked { - params.asset.safeTransferFrom({ - from: msg.sender, - to: address(this), - value: createAmounts.deposit + createAmounts.protocolFee - }); - } + // Interactions: transfer the deposit amount. + params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); // Interactions: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { diff --git a/src/abstracts/SablierV2Base.sol b/src/abstracts/SablierV2Base.sol deleted file mode 100644 index 2f4ba1904..000000000 --- a/src/abstracts/SablierV2Base.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.8.22; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { IAdminable } from "../interfaces/IAdminable.sol"; -import { ISablierV2Base } from "../interfaces/ISablierV2Base.sol"; -import { ISablierV2Comptroller } from "../interfaces/ISablierV2Comptroller.sol"; -import { Errors } from "../libraries/Errors.sol"; -import { Adminable } from "./Adminable.sol"; -import { NoDelegateCall } from "./NoDelegateCall.sol"; - -/// @title SablierV2Base -/// @notice See the documentation in {ISablierV2Base}. -abstract contract SablierV2Base is - NoDelegateCall, // 0 inherited components - ISablierV2Base, // 1 inherited component - Adminable // 1 inherited component -{ - using SafeERC20 for IERC20; - - /*////////////////////////////////////////////////////////////////////////// - STATE VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - - /// @inheritdoc ISablierV2Base - UD60x18 public constant override MAX_FEE = UD60x18.wrap(0.1e18); - - /// @inheritdoc ISablierV2Base - ISablierV2Comptroller public override comptroller; - - /// @inheritdoc ISablierV2Base - mapping(IERC20 asset => uint128 revenues) public override protocolRevenues; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Emits a {TransferAdmin} event. - /// @param initialAdmin The address of the initial contract admin. - /// @param initialComptroller The address of the initial comptroller. - constructor(address initialAdmin, ISablierV2Comptroller initialComptroller) { - admin = initialAdmin; - comptroller = initialComptroller; - emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); - } - - /*////////////////////////////////////////////////////////////////////////// - USER-FACING NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @inheritdoc ISablierV2Base - function claimProtocolRevenues(IERC20 asset) external override onlyAdmin { - // Checks: the protocol revenues are not zero. - uint128 revenues = protocolRevenues[asset]; - if (revenues == 0) { - revert Errors.SablierV2Base_NoProtocolRevenues(asset); - } - - // Effects: set the protocol revenues to zero. - protocolRevenues[asset] = 0; - - // Interactions: perform the ERC-20 transfer to pay the protocol revenues. - asset.safeTransfer({ to: msg.sender, value: revenues }); - - // Log the claim of the protocol revenues. - emit ISablierV2Base.ClaimProtocolRevenues({ admin: msg.sender, asset: asset, protocolRevenues: revenues }); - } - - /// @inheritdoc ISablierV2Base - function setComptroller(ISablierV2Comptroller newComptroller) external override onlyAdmin { - // Effects: set the new comptroller. - ISablierV2Comptroller oldComptroller = comptroller; - comptroller = newComptroller; - - // Log the change of the comptroller. - emit ISablierV2Base.SetComptroller({ - admin: msg.sender, - oldComptroller: oldComptroller, - newComptroller: newComptroller - }); - } -} diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 24993f5ec..3c43bb470 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -1,27 +1,29 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.22; +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2Comptroller } from "../interfaces/ISablierV2Comptroller.sol"; -import { ISablierV2Lockup } from "../interfaces/ISablierV2Lockup.sol"; -import { ISablierV2NFTDescriptor } from "../interfaces/ISablierV2NFTDescriptor.sol"; import { ISablierV2Recipient } from "../interfaces/hooks/ISablierV2Recipient.sol"; import { ISablierV2Sender } from "../interfaces/hooks/ISablierV2Sender.sol"; +import { ISablierV2Lockup } from "../interfaces/ISablierV2Lockup.sol"; +import { ISablierV2NFTDescriptor } from "../interfaces/ISablierV2NFTDescriptor.sol"; import { Errors } from "../libraries/Errors.sol"; import { Lockup } from "../types/DataTypes.sol"; -import { SablierV2Base } from "./SablierV2Base.sol"; +import { Adminable } from "./Adminable.sol"; +import { NoDelegateCall } from "./NoDelegateCall.sol"; /// @title SablierV2Lockup /// @notice See the documentation in {ISablierV2Lockup}. abstract contract SablierV2Lockup is + NoDelegateCall, // 0 inherited components + Adminable, // 1 inherited components IERC4906, // 2 inherited components - SablierV2Base, // 4 inherited components - ISablierV2Lockup, // 5 inherited components + ISablierV2Lockup, // 4 inherited components ERC721 // 6 inherited components { using SafeERC20 for IERC20; @@ -30,6 +32,9 @@ abstract contract SablierV2Lockup is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierV2Lockup + UD60x18 public constant override MAX_BROKER_FEE = UD60x18.wrap(0.1e18); + /// @inheritdoc ISablierV2Lockup uint256 public override nextStreamId; @@ -43,17 +48,13 @@ abstract contract SablierV2Lockup is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ + /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. - /// @param initialComptroller The address of the initial comptroller. /// @param initialNFTDescriptor The address of the initial NFT descriptor. - constructor( - address initialAdmin, - ISablierV2Comptroller initialComptroller, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - SablierV2Base(initialAdmin, initialComptroller) - { + constructor(address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor) { + admin = initialAdmin; nftDescriptor = initialNFTDescriptor; + emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/src/interfaces/ISablierV2Base.sol b/src/interfaces/ISablierV2Base.sol deleted file mode 100644 index 84b6d10cd..000000000 --- a/src/interfaces/ISablierV2Base.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { IAdminable } from "./IAdminable.sol"; -import { ISablierV2Comptroller } from "./ISablierV2Comptroller.sol"; - -/// @title ISablierV2Base -/// @notice Base logic for all Sablier V2 streaming contracts. -interface ISablierV2Base is IAdminable { - /*////////////////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Emitted when the admin claims all protocol revenues accrued for a particular ERC-20 asset. - /// @param admin The address of the contract admin. - /// @param asset The contract address of the ERC-20 asset the protocol revenues have been claimed for. - /// @param protocolRevenues The amount of protocol revenues claimed, denoted in units of the asset's decimals. - event ClaimProtocolRevenues(address indexed admin, IERC20 indexed asset, uint128 protocolRevenues); - - /// @notice Emitted when the admin sets a new comptroller contract. - /// @param admin The address of the contract admin. - /// @param oldComptroller The address of the old comptroller contract. - /// @param newComptroller The address of the new comptroller contract. - event SetComptroller( - address indexed admin, ISablierV2Comptroller oldComptroller, ISablierV2Comptroller newComptroller - ); - - /*////////////////////////////////////////////////////////////////////////// - CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Retrieves the maximum fee that can be charged by the protocol or a broker, denoted as a fixed-point - /// number where 1e18 is 100%. - /// @dev This value is hard coded as a constant. - function MAX_FEE() external view returns (UD60x18); - - /// @notice Retrieves the address of the comptroller contract, responsible for the Sablier V2 protocol - /// configuration. - function comptroller() external view returns (ISablierV2Comptroller); - - /// @notice Retrieves the protocol revenues accrued for the provided ERC-20 asset, in units of the asset's - /// decimals. - /// @param asset The contract address of the ERC-20 asset to query. - function protocolRevenues(IERC20 asset) external view returns (uint128 revenues); - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Claims all accumulated protocol revenues for the provided ERC-20 asset. - /// - /// @dev Emits a {ClaimProtocolRevenues} event. - /// - /// Requirements: - /// - `msg.sender` must be the contract admin. - /// - /// @param asset The contract address of the ERC-20 asset for which to claim protocol revenues. - function claimProtocolRevenues(IERC20 asset) external; - - /// @notice Assigns a new comptroller contract responsible for the protocol configuration. - /// - /// @dev Emits a {SetComptroller} event. - /// - /// Notes: - /// - Does not revert if the comptroller is the same. - /// - /// Requirements: - /// - `msg.sender` must be the contract admin. - /// - /// @param newComptroller The address of the new comptroller contract. - function setComptroller(ISablierV2Comptroller newComptroller) external; -} diff --git a/src/interfaces/ISablierV2Comptroller.sol b/src/interfaces/ISablierV2Comptroller.sol deleted file mode 100644 index 34bb413e0..000000000 --- a/src/interfaces/ISablierV2Comptroller.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { IAdminable } from "./IAdminable.sol"; - -/// @title ISablierV2Comptroller -/// @notice This contract is in charge of the Sablier V2 protocol configuration, handling such values as the -/// protocol fees. -interface ISablierV2Comptroller is IAdminable { - /*////////////////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Emitted when the admin sets a new protocol fee for the provided ERC-20 asset. - /// @param admin The address of the contract admin. - /// @param asset The contract address of the ERC-20 asset the new protocol fee has been set for. - /// @param oldProtocolFee The old protocol fee, denoted as a fixed-point number. - /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number. - event SetProtocolFee(address indexed admin, IERC20 indexed asset, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); - - /*////////////////////////////////////////////////////////////////////////// - CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Retrieves the protocol fee for all streams created with the provided ERC-20 asset. - /// @param asset The contract address of the ERC-20 asset to query. - /// @return fee The protocol fee denoted as a fixed-point number where 1e18 is 100%. - function protocolFees(IERC20 asset) external view returns (UD60x18 fee); - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Sets a new protocol fee that will be charged on all streams created with the provided ERC-20 asset. - /// - /// @dev Emits a {SetProtocolFee} event. - /// - /// Notes: - /// - The fee is not denoted in units of the asset's decimals; it is a fixed-point number. Refer to the - /// PRBMath documentation for more detail on the logic of UD60x18. - /// - Does not revert if the fee is the same. - /// - /// Requirements: - /// - `msg.sender` must be the contract admin. - /// - /// @param asset The contract address of the ERC-20 asset to update the fee for. - /// @param newProtocolFee The new protocol fee, denoted as a fixed-point number where 1e18 is 100%. - function setProtocolFee(IERC20 asset, UD60x18 newProtocolFee) external; -} diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index e129860e8..b1c465d51 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -3,15 +3,16 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { Lockup } from "../types/DataTypes.sol"; -import { ISablierV2Base } from "./ISablierV2Base.sol"; +import { IAdminable } from "./IAdminable.sol"; import { ISablierV2NFTDescriptor } from "./ISablierV2NFTDescriptor.sol"; /// @title ISablierV2Lockup /// @notice Common logic between all Sablier V2 Lockup streaming contracts. interface ISablierV2Lockup is - ISablierV2Base, // 1 inherited component + IAdminable, // 0 inherited components IERC721Metadata // 2 inherited components { /*////////////////////////////////////////////////////////////////////////// @@ -131,6 +132,11 @@ interface ISablierV2Lockup is /// @param streamId The stream id for the query. function isWarm(uint256 streamId) external view returns (bool result); + /// @notice Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point + /// number where 1e18 is 100%. + /// @dev This value is hard coded as a constant. + function MAX_BROKER_FEE() external view returns (UD60x18); + /// @notice Counter for stream ids, used in the create functions. function nextStreamId() external view returns (uint256); diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index 2bf973b8d..d789e4692 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -18,8 +18,8 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @param funder The address which has funded the stream. /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream. /// @param recipient The address toward which to stream the assets. - /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the - /// broker fee amount, all denoted in units of the asset's decimals. + /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset 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. @@ -117,7 +117,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// Requirements: /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. - /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. + /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`. /// - `params.startTime` must be less than the first segment's timestamp. /// - The segment timestamps must be arranged in ascending order. diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index 5ffc6f5e9..c13ba8638 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -18,8 +18,8 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param funder The address which funded the stream. /// @param sender The address streaming the assets, with the ability to cancel the stream. /// @param recipient The address receiving the assets. - /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the - /// broker fee amount, all denoted in units of the asset's decimals. + /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset 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. @@ -112,7 +112,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// Requirements: /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. - /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. + /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. /// - `params.range.start` must be greater than zero. /// - `params.range.start` must be less than `params.range.end`. /// - If set, `params.range.cliff` must be greater than `params.range.start`. diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 14f47aac8..457c557cf 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -18,8 +18,8 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// @param funder The address which has funded the stream. /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream. /// @param recipient The address toward which to stream the assets. - /// @param amounts Struct containing (i) the deposit amount, (ii) the protocol fee amount, and (iii) the - /// broker fee amount, all denoted in units of the asset's decimals. + /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset 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. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index fad6a551f..cf2b1b5e3 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; @@ -18,19 +17,12 @@ library Errors { /// @notice Thrown when trying to delegate call to a function that disallows delegate calls. error DelegateCall(); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-BASE - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Thrown when trying to claim protocol revenues for an asset with no accrued revenues. - error SablierV2Base_NoProtocolRevenues(IERC20 asset); - /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when the broker fee exceeds the maximum allowed fee. - error SablierV2Lockup_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxFee); + error SablierV2Lockup_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxBrokerFee); /// @notice Thrown when trying to create a stream with a zero deposit amount. error SablierV2Lockup_DepositAmountZero(); @@ -47,9 +39,6 @@ library Errors { /// @notice Thrown when trying to withdraw an amount greater than the withdrawable amount. error SablierV2Lockup_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); - /// @notice Thrown when the protocol fee exceeds the maximum allowed fee. - error SablierV2Lockup_ProtocolFeeTooHigh(UD60x18 protocolFee, UD60x18 maxFee); - /// @notice Thrown when trying to cancel or renounce a canceled stream. error SablierV2Lockup_StreamCanceled(uint256 streamId); diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 88c372498..71a8c738f 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -13,46 +13,36 @@ library Helpers { INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Checks that neither fee is greater than `maxFee`, and then calculates the protocol fee amount, the - /// broker fee amount, and the deposit amount from the total amount. - function checkAndCalculateFees( + /// @dev Checks the broker fee is not greater than `maxBrokerFee`, and then calculates the broker fee amount and the + /// deposit amount from the total amount. + function checkAndCalculateBrokerFee( uint128 totalAmount, - UD60x18 protocolFee, UD60x18 brokerFee, - UD60x18 maxFee + UD60x18 maxBrokerFee ) internal pure returns (Lockup.CreateAmounts memory amounts) { - // When the total amount is zero, the fees are also zero. + // When the total amount is zero, the broker fee is also zero. if (totalAmount == 0) { - return Lockup.CreateAmounts(0, 0, 0); + return Lockup.CreateAmounts(0, 0); } - // Checks: the protocol fee is not greater than `maxFee`. - if (protocolFee.gt(maxFee)) { - revert Errors.SablierV2Lockup_ProtocolFeeTooHigh(protocolFee, maxFee); + // Checks: the broker fee is not greater than `maxBrokerFee`. + if (brokerFee.gt(maxBrokerFee)) { + revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee); } - // Checks: the broker fee is not greater than `maxFee`. - if (brokerFee.gt(maxFee)) { - revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxFee); - } - - // Calculate the protocol fee amount. - // The cast to uint128 is safe because the maximum fee is hard coded. - amounts.protocolFee = uint128(ud(totalAmount).mul(protocolFee).intoUint256()); // Calculate the broker fee amount. // The cast to uint128 is safe because the maximum fee is hard coded. amounts.brokerFee = uint128(ud(totalAmount).mul(brokerFee).intoUint256()); - // Assert that the total amount is strictly greater than the sum of the protocol fee amount and the - // broker fee amount. - assert(totalAmount > amounts.protocolFee + amounts.brokerFee); + // Assert that the total amount is strictly greater than the broker fee amount. + assert(totalAmount > amounts.brokerFee); - // Calculate the deposit amount (the amount to stream, net of fees). - amounts.deposit = totalAmount - amounts.protocolFee - amounts.brokerFee; + // Calculate the deposit amount (the amount to stream, net of the broker fee). + amounts.deposit = totalAmount - amounts.brokerFee; } /// @dev Checks the parameters of the {SablierV2LockupDynamic-_createWithTimestamps} function. diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 6743515ad..860623037 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -28,11 +28,11 @@ struct Broker { /// @notice Namespace for the structs used in both {SablierV2LockupLinear} and {SablierV2LockupDynamic}. library Lockup { - /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, all denoted in units - /// of the asset's decimals. - /// @dev Because the deposited and the withdrawn amount are often read together, declaring them in - /// the same slot saves gas. - /// @param deposited The initial amount deposited in the stream, net of fees. + /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, both denoted in units of the asset's + /// decimals. + /// @dev Because the deposited and the withdrawn amount are often read together, declaring them in the same slot + /// saves gas. + /// @param deposited The initial amount deposited in the stream, net of broker fee. /// @param withdrawn The cumulative amount withdrawn from the stream. /// @param refunded The amount refunded to the sender. Unless the stream was canceled, this is always zero. struct Amounts { @@ -43,14 +43,12 @@ library Lockup { uint128 refunded; } - /// @notice Struct encapsulating the deposit amount, the protocol fee amount, and the broker fee amount, - /// all denoted in units of the asset's decimals. + /// @notice Struct encapsulating the deposit amount and the broker fee amount, both denoted in units of the asset's + /// decimals. /// @param deposit The amount to deposit in the stream. - /// @param protocolFee The protocol fee amount. /// @param brokerFee The broker fee amount. struct CreateAmounts { uint128 deposit; - uint128 protocolFee; uint128 brokerFee; } @@ -79,7 +77,7 @@ library Lockup { /// @param isDepleted Boolean indicating if the stream is depleted. /// @param isStream Boolean indicating if the struct entity exists. /// @param isTransferable Boolean indicating if the stream NFT is transferable. - /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, all denoted in units of the + /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, both denoted in units of the /// asset's decimals. struct Stream { // slot 0 @@ -104,8 +102,8 @@ library LockupDynamic { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. @@ -129,8 +127,8 @@ library LockupDynamic { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. @@ -203,8 +201,8 @@ library LockupLinear { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. @@ -226,8 +224,8 @@ library LockupLinear { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. @@ -288,8 +286,8 @@ library LockupTranched { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. @@ -313,8 +311,8 @@ library LockupTranched { /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the /// same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any potential - /// fees, all denoted in units of the asset's decimals. + /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// broker fee, both denoted in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset used for streaming. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. diff --git a/test/Base.t.sol b/test/Base.t.sol index 0874e8b17..2cf279f84 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -3,12 +3,10 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; @@ -40,7 +38,6 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2Comptroller internal comptroller; ERC20Mock internal dai; Defaults internal defaults; GoodRecipient internal goodRecipient; @@ -128,17 +125,15 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi /// for contracts deployed via `CREATE` are based on the caller-and-nonce-hash). function deployCoreConditionally() internal { if (!isTestOptimizedProfile()) { - comptroller = new SablierV2Comptroller(users.admin); nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT()); - lockupLinear = new SablierV2LockupLinear(users.admin, comptroller, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT()); + lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_COUNT()); + lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(users.admin, nftDescriptor, defaults.MAX_COUNT()); } else { - (comptroller, lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = - deployOptimizedCore(users.admin, defaults.MAX_COUNT(), defaults.MAX_COUNT()); + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = + deployOptimizedCore(users.admin, defaults.MAX_COUNT()); } - vm.label({ account: address(comptroller), newLabel: "Comptroller" }); vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index c5138e1d6..d831ad648 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; @@ -37,7 +36,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { address sender; address recipient; uint128 withdrawAmount; - UD60x18 protocolFee; uint40 startTime; uint40 warpTimestamp; LockupDynamic.Segment[] segments; @@ -66,14 +64,11 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { uint256 actualBrokerBalance; uint256 actualHolderBalance; uint256 actualNextStreamId; - uint256 actualProtocolRevenues; Lockup.CreateAmounts createAmounts; uint256 expectedBrokerBalance; uint256 expectedHolderBalance; - uint256 expectedProtocolRevenues; uint256 expectedNextStreamId; uint256 initialBrokerBalance; - uint256 initialProtocolRevenues; uint128 totalAmount; // Withdraw vars uint128 actualWithdrawnAmount; @@ -92,7 +87,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. /// - It should bump the next stream id. - /// - It should record the protocol fee. /// - It should mint the NFT. /// - It should emit a {CreateLockupDynamicStream} event. /// - It may make a withdrawal. @@ -110,32 +104,25 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { /// - Start time in the future /// - Start time equal and not equal to the first segment timestamp /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero /// - Multiple values for the withdraw amount, including zero /// - The whole gamut of stream statuses function testForkFuzz_LockupDynamic_CreateWithdrawCancel(Params memory params) external { checkUsers(params.sender, params.recipient, params.broker.account, address(lockupDynamic)); vm.assume(params.segments.length != 0); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); - // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the segment amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts({ upperBound: uint128(initialHolderBalance), segments: params.segments, - protocolFee: params.protocolFee, brokerFee: params.broker.fee }); - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: ASSET, newProtocolFee: params.protocolFee }); - // Make the holder the caller. changePrank(HOLDER); @@ -143,9 +130,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { CREATE //////////////////////////////////////////////////////////////////////////*/ - // Load the pre-create protocol revenues. - vars.initialProtocolRevenues = lockupDynamic.protocolRevenues(ASSET); - // Load the pre-create asset balances. vars.balances = getTokenBalances(address(ASSET), Solarray.addresses(address(lockupDynamic), params.broker.account)); @@ -224,11 +208,6 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupDynamic.protocolRevenues(ASSET); - vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "post-create protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; @@ -242,8 +221,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vars.actualBrokerBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupDynamicBalance = - vars.initialLockupDynamicBalance + vars.createAmounts.deposit + vars.createAmounts.protocolFee; + vars.expectedLockupDynamicBalance = vars.initialLockupDynamicBalance + vars.createAmounts.deposit; assertEq( vars.actualLockupDynamicBalance, vars.expectedLockupDynamicBalance, diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index c76b964d3..603227a76 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { ud } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; @@ -38,7 +38,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { address recipient; uint128 totalAmount; uint128 withdrawAmount; - UD60x18 protocolFee; uint40 warpTimestamp; LockupLinear.Range range; Broker broker; @@ -65,13 +64,10 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Create vars uint256 actualBrokerBalance; uint256 actualNextStreamId; - uint256 actualProtocolRevenues; Lockup.CreateAmounts createAmounts; uint256 expectedBrokerBalance; uint256 expectedNextStreamId; - uint256 expectedProtocolRevenues; uint256 initialBrokerBalance; - uint256 initialProtocolRevenues; // Withdraw vars uint128 actualWithdrawnAmount; uint128 expectedWithdrawnAmount; @@ -89,7 +85,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. /// - It should bump the next stream id. - /// - It should record the protocol fee. /// - It should mint the NFT. /// - It should emit a {MetadataUpdate} event /// - It should emit a {CreateLockupLinearStream} event. @@ -105,7 +100,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { /// - Multiple values for the total amount /// - Multiple values for the cliff time and the end time /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero /// - Multiple values for the withdraw amount, including zero /// - Start time in the past /// - Start time in the present @@ -117,8 +111,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Bound the parameters. uint40 currentTime = getBlockTimestamp(); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.range.start = boundUint40(params.range.start, currentTime - 1000 seconds, currentTime + 10_000 seconds); params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); @@ -131,10 +124,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { MAX_UNIX_TIMESTAMP ); - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: ASSET, newProtocolFee: params.protocolFee }); - // Make the holder the caller. changePrank(HOLDER); @@ -142,9 +131,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { CREATE //////////////////////////////////////////////////////////////////////////*/ - // Load the pre-create protocol revenues. Vars memory vars; - vars.initialProtocolRevenues = lockupLinear.protocolRevenues(ASSET); // Load the pre-create asset balances. vars.balances = @@ -152,10 +139,9 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { vars.initialLockupLinearBalance = vars.balances[0]; vars.initialBrokerBalance = vars.balances[1]; - // Calculate the fee amounts and the deposit amount. - vars.createAmounts.protocolFee = ud(params.totalAmount).mul(params.protocolFee).intoUint128(); + // Calculate the broker fee amount and the deposit amount. vars.createAmounts.brokerFee = ud(params.totalAmount).mul(params.broker.fee).intoUint128(); - vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.protocolFee - vars.createAmounts.brokerFee; + vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.brokerFee; vars.streamId = lockupLinear.nextStreamId(); @@ -214,11 +200,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupLinear.protocolRevenues(ASSET); - vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "post-create protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupLinear.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; @@ -232,8 +213,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { vars.actualBrokerBalance = vars.balances[2]; // Assert that the LockupLinear contract's balance has been updated. - vars.expectedLockupLinearBalance = - vars.initialLockupLinearBalance + vars.createAmounts.deposit + vars.createAmounts.protocolFee; + vars.expectedLockupLinearBalance = vars.initialLockupLinearBalance + vars.createAmounts.deposit; assertEq(vars.actualLockupLinearBalance, vars.expectedLockupLinearBalance, "post-create LockupLinear balance"); // Assert that the holder's balance has been updated. diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol index 6331e1b31..173b6e112 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/fork/LockupTranched.t.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; @@ -37,7 +36,6 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { address sender; address recipient; uint128 withdrawAmount; - UD60x18 protocolFee; uint40 startTime; uint40 warpTimestamp; LockupTranched.Tranche[] tranches; @@ -66,14 +64,11 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { uint256 actualBrokerBalance; uint256 actualHolderBalance; uint256 actualNextStreamId; - uint256 actualProtocolRevenues; Lockup.CreateAmounts createAmounts; uint256 expectedBrokerBalance; uint256 expectedHolderBalance; - uint256 expectedProtocolRevenues; uint256 expectedNextStreamId; uint256 initialBrokerBalance; - uint256 initialProtocolRevenues; uint128 totalAmount; // Withdraw vars uint128 actualWithdrawnAmount; @@ -92,7 +87,6 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. /// - It should bump the next stream id. - /// - It should record the protocol fee. /// - It should mint the NFT. /// - It should emit a {CreateLockupTranchedStream} event. /// - It may make a withdrawal. @@ -109,33 +103,26 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { /// - Start time in the present /// - Start time in the future /// - Start time equal and not equal to the first tranche timestamp - /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero + /// - Multiple values for the broker fee, including zero. /// - Multiple values for the withdraw amount, including zero /// - The whole gamut of stream statuses function testForkFuzz_LockupTranched_CreateWithdrawCancel(Params memory params) external { checkUsers(params.sender, params.recipient, params.broker.account, address(lockupTranched)); vm.assume(params.tranches.length != 0); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - params.protocolFee = _bound(params.protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); // Fuzz the tranche timestamps. fuzzTrancheTimestamps(params.tranches, params.startTime); - // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the tranche amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts({ upperBound: uint128(initialHolderBalance), tranches: params.tranches, - protocolFee: params.protocolFee, brokerFee: params.broker.fee }); - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: ASSET, newProtocolFee: params.protocolFee }); - // Make the holder the caller. changePrank(HOLDER); @@ -143,9 +130,6 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { CREATE //////////////////////////////////////////////////////////////////////////*/ - // Load the pre-create protocol revenues. - vars.initialProtocolRevenues = lockupTranched.protocolRevenues(ASSET); - // Load the pre-create asset balances. vars.balances = getTokenBalances(address(ASSET), Solarray.addresses(address(lockupTranched), params.broker.account)); @@ -226,11 +210,6 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupTranched.protocolRevenues(ASSET); - vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "post-create protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; @@ -244,8 +223,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { vars.actualBrokerBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupTranchedBalance = - vars.initialLockupTranchedBalance + vars.createAmounts.deposit + vars.createAmounts.protocolFee; + vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance + vars.createAmounts.deposit; assertEq( vars.actualLockupTranchedBalance, vars.expectedLockupTranchedBalance, diff --git a/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol b/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol deleted file mode 100644 index 2efdc66a1..000000000 --- a/test/integration/concrete/comptroller/protocol-fees/protocolFees.t.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -contract ProtocolFees_Integration_Concrete_Test is Integration_Test { - function setUp() public override { - Integration_Test.setUp(); - - // Make the Admin the caller in this test suite. - changePrank({ msgSender: users.admin }); - } - - function test_ProtocolFees_ProtocolFeeNotSet() external { - UD60x18 actualProtocolFee = comptroller.protocolFees(dai); - UD60x18 expectedProtocolFee = ZERO; - assertEq(actualProtocolFee, expectedProtocolFee, "protocolFees"); - } - - modifier givenProtocolFeeSet() { - comptroller.setProtocolFee({ asset: dai, newProtocolFee: defaults.PROTOCOL_FEE() }); - _; - } - - function test_ProtocolFees() external givenProtocolFeeSet { - UD60x18 actualProtocolFee = comptroller.protocolFees(dai); - UD60x18 expectedProtocolFee = defaults.PROTOCOL_FEE(); - assertEq(actualProtocolFee, expectedProtocolFee, "protocolFees"); - } -} diff --git a/test/integration/concrete/comptroller/protocol-fees/protocolFees.tree b/test/integration/concrete/comptroller/protocol-fees/protocolFees.tree deleted file mode 100644 index c2e81b8d8..000000000 --- a/test/integration/concrete/comptroller/protocol-fees/protocolFees.tree +++ /dev/null @@ -1,5 +0,0 @@ -protocolFees.t.sol -├── given the protocol fee has not been set -│ └── it should return zero -└── given the protocol fee has been set - └── it should return the correct protocol fee diff --git a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol deleted file mode 100644 index fff14e693..000000000 --- a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.s.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Errors } from "src/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -contract SetProtocolFee_Integration_Concrete_Test is Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: MAX_FEE }); - } - - /// @dev The Admin is the default caller in the comptroller tests. - modifier whenCallerAdmin() { - _; - } - - function test_SetProtocolFee_SameFee() external whenCallerAdmin { - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetProtocolFee({ admin: users.admin, asset: dai, oldProtocolFee: ZERO, newProtocolFee: ZERO }); - - // Set the same protocol fee. - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); - - // Assert that the protocol fee has not changed. - UD60x18 actualProtocolFee = comptroller.protocolFees(dai); - UD60x18 expectedProtocolFee = ZERO; - assertEq(actualProtocolFee, expectedProtocolFee, "protocolFee"); - } - - modifier whenNewFee() { - _; - } - - function test_SetProtocolFee() external whenCallerAdmin whenNewFee { - UD60x18 newProtocolFee = defaults.PROTOCOL_FEE(); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetProtocolFee({ admin: users.admin, asset: dai, oldProtocolFee: ZERO, newProtocolFee: newProtocolFee }); - - // Set the new protocol fee. - comptroller.setProtocolFee({ asset: dai, newProtocolFee: newProtocolFee }); - - // Assert that the protocol fee has been updated. - UD60x18 actualProtocolFee = comptroller.protocolFees(dai); - UD60x18 expectedProtocolFee = newProtocolFee; - assertEq(actualProtocolFee, expectedProtocolFee, "protocolFee"); - } -} diff --git a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree b/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree deleted file mode 100644 index ed8ffcc23..000000000 --- a/test/integration/concrete/comptroller/set-protocol-fee/setProtocolFee.tree +++ /dev/null @@ -1,10 +0,0 @@ -setProtocolFee.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the new protocol fee is the same as the current protocol fee - │ ├── it should re-set the protocol fee - │ └── it should emit a {SetProtocolFee} event - └── when the new protocol fee is not the same as the current protocol fee - ├── it should set the new protocol fee - └── it should emit a {SetProtocolFee} event \ No newline at end of file diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index f4e92bdde..dfb65c75d 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -8,8 +8,6 @@ import { Integration_Test } from "../../Integration.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { ClaimProtocolRevenues_Integration_Concrete_Test } from - "../lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol"; import { GetAsset_Integration_Concrete_Test } from "../lockup/get-asset/getAsset.t.sol"; import { GetDepositedAmount_Integration_Concrete_Test } from "../lockup/get-deposited-amount/getDepositedAmount.t.sol"; import { GetEndTime_Integration_Concrete_Test } from "../lockup/get-end-time/getEndTime.t.sol"; @@ -24,10 +22,8 @@ import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDe import { IsStream_Integration_Concrete_Test } from "../lockup/is-stream/isStream.t.sol"; import { IsTransferable_Integration_Concrete_Test } from "../lockup/is-transferable/isTransferable.t.sol"; import { IsWarm_Integration_Concrete_Test } from "../lockup/is-warm/isWarm.t.sol"; -import { ProtocolRevenues_Integration_Concrete_Test } from "../lockup/protocol-revenues/protocolRevenues.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "../lockup/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce.t.sol"; -import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptroller/setComptroller.t.sol"; import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; @@ -50,8 +46,7 @@ abstract contract LockupDynamic_Integration_Concrete_Test is Integration_Test, L Integration_Test.setUp(); LockupDynamic_Integration_Shared_Test.setUp(); - // Cast the LockupDynamic contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Lockup(lockupDynamic); + // Cast the LockupDynamic contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupDynamic); } } @@ -98,20 +93,6 @@ contract CancelMultiple_LockupDynamic_Integration_Concrete_Test is } } -contract ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Concrete_Test, - ClaimProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Concrete_Test, ClaimProtocolRevenues_Integration_Concrete_Test) - { - LockupDynamic_Integration_Concrete_Test.setUp(); - ClaimProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract GetAsset_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, GetAsset_Integration_Concrete_Test @@ -308,20 +289,6 @@ contract IsWarm_LockupDynamic_Integration_Concrete_Test is } } -contract ProtocolRevenues_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Concrete_Test, - ProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Concrete_Test, ProtocolRevenues_Integration_Concrete_Test) - { - LockupDynamic_Integration_Concrete_Test.setUp(); - ProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract RefundableAmountOf_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, RefundableAmountOf_Integration_Concrete_Test @@ -350,20 +317,6 @@ contract Renounce_LockupDynamic_Integration_Concrete_Test is } } -contract SetComptroller_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Concrete_Test, - SetComptroller_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Concrete_Test, SetComptroller_Integration_Concrete_Test) - { - LockupDynamic_Integration_Concrete_Test.setUp(); - SetComptroller_Integration_Concrete_Test.setUp(); - } -} - contract SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, SetNFTDescriptor_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index d5f018cca..817d6277a 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -14,21 +14,15 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In // Construct the contract. SablierV2LockupDynamic constructedLockupDynamic = new SablierV2LockupDynamic({ initialAdmin: users.admin, - initialComptroller: comptroller, initialNFTDescriptor: nftDescriptor, maxSegmentCount: defaults.MAX_COUNT() }); - // {SablierV2Base.constructor} + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupDynamic.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); - address actualComptroller = address(constructedLockupDynamic.comptroller()); - address expectedComptroller = address(comptroller); - assertEq(actualComptroller, expectedComptroller, "comptroller"); - - // {SablierV2Lockup.constructor} uint256 actualStreamId = constructedLockupDynamic.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 6c3ea8406..12dc4758b 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -125,9 +125,6 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = lockupDynamic.protocolRevenues(dai); - // Declare the range. uint40 currentTime = getBlockTimestamp(); LockupDynamic.Range memory range = @@ -140,11 +137,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupDynamic), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() - }); + expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); @@ -188,11 +181,6 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = lockupDynamic.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + defaults.PROTOCOL_FEE_AMOUNT(); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree index e1fa7ae20..48cdb0c85 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree @@ -16,7 +16,6 @@ createWithDurations.t.sol └── when the segment timestamp calculations do not overflow uint256 ├── it should create the stream ├── it should bump the next stream id - ├── it should record the protocol fee ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 621963bab..7ca13f5ae 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -41,7 +41,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is } function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { - // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_FEE` + // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_BROKER_FEE` // is hard coded to 10%. vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); uint128 totalAmount = 0; @@ -199,9 +199,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture { - // Disable both the protocol and the broker fee so that they don't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); UD60x18 brokerFee = ZERO; changePrank({ msgSender: users.sender }); @@ -227,7 +224,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is lockupDynamic.createWithTimestamps(params); } - function test_RevertGiven_ProtocolFeeTooHigh() + function test_RevertWhen_BrokerFeeTooHigh() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -240,36 +237,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum { - UD60x18 protocolFee = MAX_FEE + ud(1); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. + UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStream(); - } - - function test_RevertWhen_BrokerFeeTooHigh() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenSegmentCountNotZero - whenSegmentCountNotTooHigh - whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentTimestamp - whenSegmentTimestampsOrdered - whenEndTimeInTheFuture - whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh - { - UD60x18 brokerFee = MAX_FEE + ud(1); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_FEE)); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -285,15 +256,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh { address nonContract = address(8128); - // Set the default protocol fee so that the test does not revert due to the deposit amount not being - // equal to the sum of the segment amounts. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee(IERC20(nonContract), defaults.PROTOCOL_FEE()); changePrank({ msgSender: users.sender }); // Run the test. @@ -313,7 +279,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract { @@ -332,7 +297,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 @@ -350,7 +314,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: address(lockupDynamic), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index ee1418596..34623142c 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -31,28 +31,23 @@ createWithTimestamps.t.sol ├── when the deposit amount is not equal to the segment amounts sum │ └── it should revert └── when the deposit amount is equal to the segment amounts sum - ├── given the protocol fee is too high + ├── when the broker fee is too high │ └── it should revert - └── given the protocol fee is not too high - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should record the protocol fee - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupDynamicStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should record the protocol fee - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupDynamicStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupDynamicStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupDynamicStream} event diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index 02a7b9c5b..3cb11c643 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; @@ -9,8 +8,6 @@ import { Integration_Test } from "../../Integration.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { ClaimProtocolRevenues_Integration_Concrete_Test } from - "../lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol"; import { GetAsset_Integration_Concrete_Test } from "../lockup/get-asset/getAsset.t.sol"; import { GetDepositedAmount_Integration_Concrete_Test } from "../lockup/get-deposited-amount/getDepositedAmount.t.sol"; import { GetEndTime_Integration_Concrete_Test } from "../lockup/get-end-time/getEndTime.t.sol"; @@ -25,10 +22,8 @@ import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDe import { IsStream_Integration_Concrete_Test } from "../lockup/is-stream/isStream.t.sol"; import { IsTransferable_Integration_Concrete_Test } from "../lockup/is-transferable/isTransferable.t.sol"; import { IsWarm_Integration_Concrete_Test } from "../lockup/is-warm/isWarm.t.sol"; -import { ProtocolRevenues_Integration_Concrete_Test } from "../lockup/protocol-revenues/protocolRevenues.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "../lockup/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce.t.sol"; -import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptroller/setComptroller.t.sol"; import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; @@ -51,8 +46,7 @@ abstract contract LockupLinear_Integration_Concrete_Test is Integration_Test, Lo Integration_Test.setUp(); LockupLinear_Integration_Shared_Test.setUp(); - // Cast the LockupLinear contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Base(lockupLinear); + // Cast the LockupLinear contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupLinear); } } @@ -99,20 +93,6 @@ contract CancelMultiple_LockupLinear_Integration_Concrete_Test is } } -contract ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Concrete_Test, - ClaimProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Concrete_Test, ClaimProtocolRevenues_Integration_Concrete_Test) - { - LockupLinear_Integration_Concrete_Test.setUp(); - ClaimProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract GetAsset_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, GetAsset_Integration_Concrete_Test @@ -309,20 +289,6 @@ contract IsWarm_LockupLinear_Integration_Concrete_Test is } } -contract ProtocolRevenues_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Concrete_Test, - ProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Concrete_Test, ProtocolRevenues_Integration_Concrete_Test) - { - LockupLinear_Integration_Concrete_Test.setUp(); - ProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract Renounce_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, Renounce_Integration_Concrete_Test @@ -351,20 +317,6 @@ contract RefundableAmountOf_LockupLinear_Integration_Concrete_Test is } } -contract SetComptroller_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Concrete_Test, - SetComptroller_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Concrete_Test, SetComptroller_Integration_Concrete_Test) - { - LockupLinear_Integration_Concrete_Test.setUp(); - SetComptroller_Integration_Concrete_Test.setUp(); - } -} - contract SetNFTDescriptor_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, SetNFTDescriptor_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index d5a8ba385..ff221e8b9 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -12,22 +12,14 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); // Construct the contract. - SablierV2LockupLinear constructedLockupLinear = new SablierV2LockupLinear({ - initialAdmin: users.admin, - initialComptroller: comptroller, - initialNFTDescriptor: nftDescriptor - }); + SablierV2LockupLinear constructedLockupLinear = + new SablierV2LockupLinear({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor }); - // {SablierV2Base.constructor} + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupLinear.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); - address actualComptroller = address(constructedLockupLinear.comptroller()); - address expectedComptroller = address(comptroller); - assertEq(actualComptroller, expectedComptroller, "comptroller"); - - // {SablierV2Lockup.constructor} uint256 actualStreamId = constructedLockupLinear.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 1a5c5acd7..46263b07e 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -65,9 +65,6 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = lockupLinear.protocolRevenues(dai); - // Declare the range. uint40 currentTime = getBlockTimestamp(); LockupLinear.Range memory range = LockupLinear.Range({ @@ -77,11 +74,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is }); // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupLinear), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() - }); + expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); @@ -124,11 +117,6 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = lockupLinear.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + defaults.PROTOCOL_FEE_AMOUNT(); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree index 1b742b1c2..898296b77 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree @@ -7,7 +7,6 @@ createWithDurations.t.sol └── when the total duration calculation does not overflow uint256 ├── it should create the stream ├── it should bump the next stream id - ├── it should record the protocol fee ├── it should mint the NFT ├── it should perform the ERC-20 transfers └── it should emit a {CreateLockupLinearStream} event diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 25d952f72..00dae75bb 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -40,7 +40,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is } /// @dev It is not possible to obtain a zero deposit amount from a non-zero total amount, because the - /// `MAX_FEE` is hard coded to 10%. + /// `MAX_BROKER_FEE` is hard coded to 10%. function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); createDefaultStreamWithTotalAmount(0); @@ -160,7 +160,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStream(); } - function test_RevertGiven_ProtocolFeeTooHigh() + function test_RevertWhen_BrokerFeeTooHigh() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -170,33 +170,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenCliffTimeLessThanEndTime whenEndTimeInTheFuture { - UD60x18 protocolFee = MAX_FEE + ud(1); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. + UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStream(); - } - - function test_RevertWhen_BrokerFeeTooHigh() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime - whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh - { - UD60x18 brokerFee = MAX_FEE + ud(1); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_FEE)); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -209,7 +186,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh { address nonContract = address(8128); @@ -226,7 +202,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract { @@ -241,7 +216,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 @@ -259,7 +233,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: address(lockupLinear), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree index e1537f793..ea808de62 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree @@ -26,29 +26,24 @@ createWithTimestamps.t.sol ├── when the end time is not in the future │ └── it should revert └── when the end time is in the future - ├── given the protocol fee is too high + ├── when the broker fee is too high │ └── it should revert - └── given the protocol fee is not too high - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should record the protocol fee - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupLinearStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should record the protocol fee - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupLinearStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupLinearStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupLinearStream} event diff --git a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol index c56e06c35..2d0119b96 100644 --- a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -8,8 +8,6 @@ import { Integration_Test } from "../../Integration.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { ClaimProtocolRevenues_Integration_Concrete_Test } from - "../lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol"; import { GetAsset_Integration_Concrete_Test } from "../lockup/get-asset/getAsset.t.sol"; import { GetDepositedAmount_Integration_Concrete_Test } from "../lockup/get-deposited-amount/getDepositedAmount.t.sol"; import { GetEndTime_Integration_Concrete_Test } from "../lockup/get-end-time/getEndTime.t.sol"; @@ -24,10 +22,8 @@ import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDe import { IsStream_Integration_Concrete_Test } from "../lockup/is-stream/isStream.t.sol"; import { IsTransferable_Integration_Concrete_Test } from "../lockup/is-transferable/isTransferable.t.sol"; import { IsWarm_Integration_Concrete_Test } from "../lockup/is-warm/isWarm.t.sol"; -import { ProtocolRevenues_Integration_Concrete_Test } from "../lockup/protocol-revenues/protocolRevenues.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "../lockup/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce.t.sol"; -import { SetComptroller_Integration_Concrete_Test } from "../lockup/set-comptroller/setComptroller.t.sol"; import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; @@ -53,8 +49,7 @@ abstract contract LockupTranched_Integration_Concrete_Test is Integration_Test.setUp(); LockupTranched_Integration_Shared_Test.setUp(); - // Cast the LockupTranched contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Lockup(lockupTranched); + // Cast the LockupTranched contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupTranched); } } @@ -105,20 +100,6 @@ contract CancelMultiple_LockupTranched_Integration_Concrete_Test is } } -contract ClaimProtocolRevenues_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Concrete_Test, - ClaimProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupTranched_Integration_Concrete_Test, ClaimProtocolRevenues_Integration_Concrete_Test) - { - LockupTranched_Integration_Concrete_Test.setUp(); - ClaimProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract GetAsset_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, GetAsset_Integration_Concrete_Test @@ -315,20 +296,6 @@ contract IsWarm_LockupTranched_Integration_Concrete_Test is } } -contract ProtocolRevenues_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Concrete_Test, - ProtocolRevenues_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupTranched_Integration_Concrete_Test, ProtocolRevenues_Integration_Concrete_Test) - { - LockupTranched_Integration_Concrete_Test.setUp(); - ProtocolRevenues_Integration_Concrete_Test.setUp(); - } -} - contract RefundableAmountOf_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, RefundableAmountOf_Integration_Concrete_Test @@ -357,20 +324,6 @@ contract Renounce_LockupTranched_Integration_Concrete_Test is } } -contract SetComptroller_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Concrete_Test, - SetComptroller_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(LockupTranched_Integration_Concrete_Test, SetComptroller_Integration_Concrete_Test) - { - LockupTranched_Integration_Concrete_Test.setUp(); - SetComptroller_Integration_Concrete_Test.setUp(); - } -} - contract SetNFTDescriptor_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, SetNFTDescriptor_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol index 6ff85982a..bda7ba84f 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -14,21 +14,15 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ // Construct the contract. SablierV2LockupTranched constructedLockupTranched = new SablierV2LockupTranched({ initialAdmin: users.admin, - initialComptroller: comptroller, initialNFTDescriptor: nftDescriptor, maxTrancheCount: defaults.MAX_COUNT() }); - // {SablierV2Base.constructor} + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupTranched.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); - address actualComptroller = address(constructedLockupTranched.comptroller()); - address expectedComptroller = address(comptroller); - assertEq(actualComptroller, expectedComptroller, "comptroller"); - - // {SablierV2Lockup.constructor} uint256 actualStreamId = constructedLockupTranched.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 39575b99a..000c2b315 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -119,9 +119,6 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = lockupTranched.protocolRevenues(dai); - // Declare the range. uint40 currentTime = getBlockTimestamp(); LockupTranched.Range memory range = @@ -134,11 +131,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is tranches[2].timestamp = tranches[1].timestamp + tranchesWithDurations[2].duration; // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupTranched), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() - }); + expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); @@ -182,11 +175,6 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = lockupTranched.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + defaults.PROTOCOL_FEE_AMOUNT(); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree index c1d36efc7..b739c2df6 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree @@ -16,7 +16,6 @@ createWithDurations.t.sol └── when the tranche timestamp calculations do not overflow uint256 ├── it should create the stream ├── it should bump the next stream id - ├── it should record the protocol fee ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 27a8e07c3..aabc6eada 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -42,7 +42,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is } function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { - // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_FEE` + // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_BROKER_FEE` // is hard coded to 10%. vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); uint128 totalAmount = 0; @@ -200,9 +200,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture { - // Disable both the protocol and the broker fee so that they don't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); UD60x18 brokerFee = ZERO; changePrank({ msgSender: users.sender }); @@ -228,7 +225,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is lockupTranched.createWithTimestamps(params); } - function test_RevertGiven_ProtocolFeeTooHigh() + function test_RevertWhen_BrokerFeeTooHigh() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -241,36 +238,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum { - UD60x18 protocolFee = MAX_FEE + ud(1); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. + UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStream(); - } - - function test_RevertWhen_BrokerFeeTooHigh() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenTrancheCountNotZero - whenTrancheCountNotTooHigh - whenTrancheAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstTrancheTimestamp - whenTrancheTimestampsOrdered - whenEndTimeInTheFuture - whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh - { - UD60x18 brokerFee = MAX_FEE + ud(1); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_FEE)); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -286,15 +257,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh { address nonContract = address(8128); - // Set the default protocol fee so that the test does not revert due to the deposit amount not being - // equal to the sum of the tranche amounts. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee(IERC20(nonContract), defaults.PROTOCOL_FEE()); changePrank({ msgSender: users.sender }); // Run the test. @@ -314,7 +280,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract { @@ -333,7 +298,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 @@ -351,7 +315,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is asset: IERC20(asset), from: funder, to: address(lockupTranched), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree index 15667b77f..81617ee76 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -31,28 +31,23 @@ createWithTimestamps.t.sol ├── when the deposit amount is not equal to the tranche amounts sum │ └── it should revert └── when the deposit amount is equal to the tranche amounts sum - ├── given the protocol fee is too high + ├── when the broker fee is too high │ └── it should revert - └── given the protocol fee is not too high - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should record the protocol fee - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupTranchedStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should record the protocol fee - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupTranchedStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupTranchedStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupTranchedStream} event diff --git a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol deleted file mode 100644 index 5630dd404..000000000 --- a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.t.sol +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/libraries/Errors.sol"; - -import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract ClaimProtocolRevenues_Integration_Concrete_Test is - Integration_Test, - Lockup_Integration_Shared_Test -{ - function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { } - - function test_RevertWhen_CallerNotAdmin() external { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - base.claimProtocolRevenues(dai); - } - - modifier whenCallerAdmin() { - // Make the Admin the caller in the rest of this test suite. - changePrank({ msgSender: users.admin }); - _; - } - - function test_RevertGiven_ProtocolRevenuesZero() external whenCallerAdmin { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Base_NoProtocolRevenues.selector, dai)); - base.claimProtocolRevenues(dai); - } - - modifier givenProtocolRevenuesNotZero() { - // Create the default stream, which will accrue revenues for the protocol. - changePrank({ msgSender: users.sender }); - createDefaultStream(); - changePrank({ msgSender: users.admin }); - _; - } - - function test_ClaimProtocolRevenues() external whenCallerAdmin givenProtocolRevenuesNotZero { - // Expect the protocol revenues to be claimed. - uint128 protocolRevenues = defaults.PROTOCOL_FEE_AMOUNT(); - expectCallToTransfer({ to: users.admin, value: protocolRevenues }); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(base) }); - emit ClaimProtocolRevenues(users.admin, dai, protocolRevenues); - - // Claim the protocol revenues. - base.claimProtocolRevenues(dai); - - // Assert that the protocol revenues have been set to zero. - uint128 actualProtocolRevenues = base.protocolRevenues(dai); - uint128 expectedProtocolRevenues = 0; - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - } -} diff --git a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.tree b/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.tree deleted file mode 100644 index 46d8c91c0..000000000 --- a/test/integration/concrete/lockup/claim-protocol-revenues/claimProtocolRevenues.tree +++ /dev/null @@ -1,10 +0,0 @@ -claimProtocolRevenues.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── given the protocol revenues are zero - │ └── it should revert - └── given the protocol revenues are not zero - ├── it should claim the protocol revenues - ├── it should update the protocol revenues - └── it should emit a {ClaimProtocolRevenues} event diff --git a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol b/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol deleted file mode 100644 index 444964ec6..000000000 --- a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.t.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract ProtocolRevenues_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { - function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { } - - function test_ProtocolRevenues_ProtocolRevenuesZero() external { - uint128 actualProtocolRevenues = base.protocolRevenues(dai); - uint128 expectedProtocolRevenues = 0; - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - } - - modifier givenProtocolRevenuesNotZero() { - // Create the default stream, which will accrue revenues for the protocol. - changePrank({ msgSender: users.sender }); - createDefaultStream(); - changePrank({ msgSender: users.admin }); - _; - } - - function test_ProtocolRevenues() external givenProtocolRevenuesNotZero { - uint128 actualProtocolRevenues = base.protocolRevenues(dai); - uint128 expectedProtocolRevenues = defaults.PROTOCOL_FEE_AMOUNT(); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - } -} diff --git a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.tree b/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.tree deleted file mode 100644 index 7c575e2f0..000000000 --- a/test/integration/concrete/lockup/protocol-revenues/protocolRevenues.tree +++ /dev/null @@ -1,5 +0,0 @@ -protocolRevenues.t.sol -├── given the protocol revenues are zero -│ └── it should return zero -└── given the protocol revenues are not zero - └── it should return the correct protocol revenues diff --git a/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol b/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol deleted file mode 100644 index 09a585910..000000000 --- a/test/integration/concrete/lockup/set-comptroller/setComptroller.t.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { SablierV2Comptroller } from "src/SablierV2Comptroller.sol"; - -import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract SetComptroller_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { - function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { } - - function test_RevertWhen_CallerNotAdmin() external { - // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - base.setComptroller(ISablierV2Comptroller(users.eve)); - } - - modifier whenCallerAdmin() { - // Make the Admin the caller in the rest of this test suite. - changePrank({ msgSender: users.admin }); - _; - } - - function test_SetComptroller_SameComptroller() external whenCallerAdmin { - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(base) }); - emit SetComptroller(users.admin, comptroller, comptroller); - - // Re-set the comptroller. - base.setComptroller(comptroller); - - // Assert that the comptroller has not been changed. - address actualComptroller = address(base.comptroller()); - address expectedComptroller = address(comptroller); - assertEq(actualComptroller, expectedComptroller, "comptroller"); - } - - function test_SetComptroller_NewComptroller() external whenCallerAdmin { - // Deploy the new comptroller. - ISablierV2Comptroller newComptroller = new SablierV2Comptroller({ initialAdmin: users.admin }); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(base) }); - emit SetComptroller(users.admin, comptroller, newComptroller); - - // Set the new comptroller. - base.setComptroller(newComptroller); - - // Assert that the new comptroller has been set. - address actualComptroller = address(base.comptroller()); - address expectedComptroller = address(newComptroller); - assertEq(actualComptroller, expectedComptroller, "comptroller"); - } -} diff --git a/test/integration/concrete/lockup/set-comptroller/setComptroller.tree b/test/integration/concrete/lockup/set-comptroller/setComptroller.tree deleted file mode 100644 index fae51fdb9..000000000 --- a/test/integration/concrete/lockup/set-comptroller/setComptroller.tree +++ /dev/null @@ -1,10 +0,0 @@ -setComptroller.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the new comptroller is the same as the current comptroller - │ ├── it should re-set the comptroller - │ └── it should emit a {SetComptroller} event - └── when the new comptroller is not the same as the current comptroller - ├── it should set the new comptroller - └── it should emit a {SetComptroller} event diff --git a/test/integration/fuzz/comptroller/setProtocolFee.t.sol b/test/integration/fuzz/comptroller/setProtocolFee.t.sol deleted file mode 100644 index 08afb1b7d..000000000 --- a/test/integration/fuzz/comptroller/setProtocolFee.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { UD60x18, ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -contract SetProtocolFee_Integration_Fuzz_Test is Integration_Test { - modifier givenCallerAdmin() { - _; - } - - function testFuzz_SetProtocolFee(UD60x18 newProtocolFee) external givenCallerAdmin { - newProtocolFee = _bound(newProtocolFee, 1, MAX_FEE); - - // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(comptroller) }); - emit SetProtocolFee({ admin: users.admin, asset: dai, oldProtocolFee: ZERO, newProtocolFee: newProtocolFee }); - - // Set the new protocol fee. - comptroller.setProtocolFee({ asset: dai, newProtocolFee: newProtocolFee }); - - // Assert that the protocol fee has been updated. - UD60x18 actualProtocolFee = comptroller.protocolFees(dai); - UD60x18 expectedProtocolFee = newProtocolFee; - assertEq(actualProtocolFee, expectedProtocolFee, "protocolFee"); - } -} diff --git a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index 6dcde30a3..b699733fc 100644 --- a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; @@ -26,8 +25,7 @@ abstract contract LockupDynamic_Integration_Fuzz_Test is Integration_Test, Locku Integration_Test.setUp(); LockupDynamic_Integration_Shared_Test.setUp(); - // Cast the LockupDynamic contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Base(lockupDynamic); + // Cast the LockupDynamic contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupDynamic); } } diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 023157f3b..460bd39aa 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -22,15 +22,12 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is struct Vars { uint256 actualNextStreamId; address actualNFTOwner; - uint256 actualProtocolRevenues; Lockup.Status actualStatus; Lockup.CreateAmounts createAmounts; uint256 expectedNextStreamId; address expectedNFTOwner; - uint256 expectedProtocolRevenues; Lockup.Status expectedStatus; address funder; - uint128 initialProtocolRevenues; bool isCancelable; bool isSettled; LockupDynamic.Segment[] segmentsWithTimestamps; @@ -50,24 +47,17 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is Vars memory vars; fuzzSegmentDurations(segments); - // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the segment amounts and calculate the total and create amounts (deposit and broker fee). (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(segments); // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; - // Load the initial protocol revenues. - vars.initialProtocolRevenues = lockupDynamic.protocolRevenues(dai); - // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. - expectCallToTransferFrom({ - from: vars.funder, - to: address(lockupDynamic), - value: vars.createAmounts.deposit + vars.createAmounts.protocolFee - }); + expectCallToTransferFrom({ from: vars.funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -133,11 +123,6 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupDynamic.protocolRevenues(dai); - vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = users.recipient; diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 0801e2cdd..c1265443d 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -100,9 +100,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); - // Disable both the protocol and the broker fee so that they don't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); UD60x18 brokerFee = ZERO; changePrank({ msgSender: users.sender }); @@ -128,33 +125,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is lockupDynamic.createWithTimestamps(params); } - function testFuzz_RevertWhen_ProtocolFeeTooHigh(UD60x18 protocolFee) - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenSegmentCountNotZero - whenSegmentCountNotTooHigh - whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentTimestamp - whenSegmentTimestampsOrdered - whenEndTimeInTheFuture - whenDepositAmountEqualToSegmentAmountsSum - { - protocolFee = _bound(protocolFee, MAX_FEE + ud(1), MAX_UD60x18); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) - ); - createDefaultStream(); - } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) external whenNotDelegateCalled @@ -167,23 +137,22 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh { vm.assume(broker.account != address(0)); - broker.fee = _bound(broker.fee, MAX_FEE + ud(1), MAX_UD60x18); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_FEE)); + broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + ); createDefaultStreamWithBroker(broker); } struct Vars { uint256 actualNextStreamId; address actualNFTOwner; - uint256 actualProtocolRevenues; Lockup.Status actualStatus; Lockup.CreateAmounts createAmounts; uint256 expectedNextStreamId; address expectedNFTOwner; - uint256 expectedProtocolRevenues; Lockup.Status expectedStatus; bool isCancelable; bool isSettled; @@ -200,11 +169,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is /// - Start time in the future /// - Start time equal and not equal to the first segment timestamp /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero function testFuzz_CreateWithTimestamps( address funder, - LockupDynamic.CreateWithTimestamps memory params, - UD60x18 protocolFee + LockupDynamic.CreateWithTimestamps memory params ) external whenNotDelegateCalled @@ -217,34 +184,27 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 { vm.assume(funder != address(0) && params.recipient != address(0) && params.broker.account != address(0)); vm.assume(params.segments.length != 0); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - protocolFee = _bound(protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); params.transferable = true; // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); - // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the segment amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: params.segments, - protocolFee: protocolFee, brokerFee: params.broker.fee }); - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - // Make the fuzzed funder the caller in the rest of this test. changePrank(funder); @@ -255,11 +215,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupDynamic), - value: vars.createAmounts.deposit + vars.createAmounts.protocolFee - }); + expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -334,11 +290,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupDynamic.protocolRevenues(dai); - vars.expectedProtocolRevenues = vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = params.recipient; diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index a0068d4e8..140b4fec5 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -19,9 +19,6 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test.setUp(); StreamedAmountOf_Integration_Shared_Test.setUp(); - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); } @@ -102,12 +99,8 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is fuzzSegmentTimestamps(segments, defaults.START_TIME()); // Fuzz the segment amounts. - (uint128 totalAmount,) = fuzzDynamicStreamAmounts({ - upperBound: MAX_UINT128, - segments: segments, - protocolFee: ZERO, - brokerFee: ZERO - }); + (uint128 totalAmount,) = + fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: ZERO }); // Bound the time jump. uint40 firstSegmentDuration = segments[1].timestamp - segments[0].timestamp; @@ -153,12 +146,8 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is fuzzSegmentTimestamps(segments, defaults.START_TIME()); // Fuzz the segment amounts. - (uint128 totalAmount,) = fuzzDynamicStreamAmounts({ - upperBound: MAX_UINT128, - segments: segments, - protocolFee: ZERO, - brokerFee: ZERO - }); + (uint128 totalAmount,) = + fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: ZERO }); // Bound the time warps. uint40 firstSegmentDuration = segments[1].timestamp - segments[0].timestamp; diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index e604db5df..4bba84718 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -20,9 +20,6 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test.setUp(); WithdrawableAmountOf_Integration_Shared_Test.setUp(); - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); } diff --git a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/integration/fuzz/lockup-linear/LockupLinear.t.sol index eed9b9217..0d47251ed 100644 --- a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; @@ -27,8 +26,7 @@ abstract contract LockupLinear_Integration_Fuzz_Test is Integration_Test, Lockup Integration_Test.setUp(); LockupLinear_Integration_Shared_Test.setUp(); - // Cast the lockupLinear contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Base(lockupLinear); + // Cast the lockupLinear contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupLinear); } } diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index f9d2c440f..9e69b82af 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -60,15 +60,8 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Make the Sender the stream's funder (recall that the Sender is the default caller). address funder = users.sender; - // Load the initial protocol revenues. - uint128 initialProtocolRevenues = lockupLinear.protocolRevenues(dai); - // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupLinear), - value: defaults.DEPOSIT_AMOUNT() + defaults.PROTOCOL_FEE_AMOUNT() - }); + expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); @@ -116,11 +109,6 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - uint128 actualProtocolRevenues = lockupLinear.protocolRevenues(dai); - uint128 expectedProtocolRevenues = initialProtocolRevenues + defaults.PROTOCOL_FEE_AMOUNT(); - assertEq(actualProtocolRevenues, expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 641e6bc50..133b9e88a 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MAX_UD60x18, UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; @@ -59,29 +59,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); } - function testFuzz_RevertWhen_ProtocolFeeTooHigh(UD60x18 protocolFee) - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenStartTimeNotGreaterThanCliffTime - whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture - { - protocolFee = _bound(protocolFee, MAX_FEE + ud(1), MAX_UD60x18); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) - ); - createDefaultStream(); - } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) external whenNotDelegateCalled @@ -90,25 +67,23 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh { vm.assume(broker.account != address(0)); - broker.fee = _bound(broker.fee, MAX_FEE + ud(1), MAX_UD60x18); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_FEE)); + broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + ); createDefaultStreamWithBroker(broker); } struct Vars { uint256 actualNextStreamId; address actualNFTOwner; - uint256 actualProtocolRevenues; Lockup.Status actualStatus; Lockup.CreateAmounts createAmounts; uint256 expectedNextStreamId; address expectedNFTOwner; - uint256 expectedProtocolRevenues; Lockup.Status expectedStatus; - uint128 initialProtocolRevenues; } /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: @@ -122,11 +97,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is /// - Start time lower than and equal to cliff time /// - Multiple values for the cliff time and the end time /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero function testFuzz_CreateWithTimestamps( address funder, - LockupLinear.CreateWithTimestamps memory params, - UD60x18 protocolFee + LockupLinear.CreateWithTimestamps memory params ) external whenNotDelegateCalled @@ -134,7 +107,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 @@ -145,19 +117,14 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is boundUint40(params.range.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.range.end = boundUint40(params.range.end, params.range.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - protocolFee = _bound(protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.transferable = true; // Calculate the fee amounts and the deposit amount. Vars memory vars; - vars.createAmounts.protocolFee = ud(params.totalAmount).mul(protocolFee).intoUint128(); - vars.createAmounts.brokerFee = ud(params.totalAmount).mul(params.broker.fee).intoUint128(); - vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.protocolFee - vars.createAmounts.brokerFee; - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); + vars.createAmounts.brokerFee = ud(params.totalAmount).mul(params.broker.fee).intoUint128(); + vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.brokerFee; // Make the fuzzed funder the caller in this test. changePrank(funder); @@ -169,11 +136,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupLinear), - value: vars.createAmounts.deposit + vars.createAmounts.protocolFee - }); + expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -233,11 +196,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupLinear.protocolRevenues(dai); - vars.expectedProtocolRevenues = vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = params.recipient; diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 98bbd1656..0397c9af8 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -21,9 +21,6 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is StreamedAmountOf_Integration_Shared_Test.setUp(); defaultStreamId = createDefaultStream(); - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); } diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index d0b93bc64..0c3c20b46 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -34,9 +34,6 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is } modifier whenCliffTimeNotInTheFuture() { - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); _; } diff --git a/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol index deb66a89b..a07b20380 100644 --- a/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; @@ -26,8 +25,7 @@ abstract contract LockupTranched_Integration_Fuzz_Test is Integration_Test, Lock Integration_Test.setUp(); LockupTranched_Integration_Shared_Test.setUp(); - // Cast the LockupTranched contract as {ISablierV2Base} and {ISablierV2Lockup}. - base = ISablierV2Base(lockupTranched); + // Cast the LockupTranched contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupTranched); } } diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 48f82ad3e..1c95cbee3 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -22,15 +22,12 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is struct Vars { uint256 actualNextStreamId; address actualNFTOwner; - uint256 actualProtocolRevenues; Lockup.Status actualStatus; Lockup.CreateAmounts createAmounts; uint256 expectedNextStreamId; address expectedNFTOwner; - uint256 expectedProtocolRevenues; Lockup.Status expectedStatus; address funder; - uint128 initialProtocolRevenues; bool isCancelable; bool isSettled; LockupTranched.Tranche[] tranchesWithTimestamps; @@ -50,24 +47,17 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is Vars memory vars; fuzzTrancheDurations(tranches); - // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the tranche amounts and calculate the total and create amounts (deposit and broker fee). (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(tranches); // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; - // Load the initial protocol revenues. - vars.initialProtocolRevenues = lockupTranched.protocolRevenues(dai); - // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. - expectCallToTransferFrom({ - from: vars.funder, - to: address(lockupTranched), - value: vars.createAmounts.deposit + vars.createAmounts.protocolFee - }); + expectCallToTransferFrom({ from: vars.funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -133,11 +123,6 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupTranched.protocolRevenues(dai); - vars.expectedProtocolRevenues = vars.initialProtocolRevenues + vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = users.recipient; diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index d1b3ed1f7..3c673940f 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -100,9 +100,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); - // Disable both the protocol and the broker fee so that they don't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); UD60x18 brokerFee = ZERO; changePrank({ msgSender: users.sender }); @@ -128,33 +125,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is lockupTranched.createWithTimestamps(params); } - function testFuzz_RevertWhen_ProtocolFeeTooHigh(UD60x18 protocolFee) - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenTrancheCountNotZero - whenTrancheCountNotTooHigh - whenTrancheAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstTrancheTimestamp - whenTrancheTimestampsOrdered - whenEndTimeInTheFuture - whenDepositAmountEqualToTrancheAmountsSum - { - protocolFee = _bound(protocolFee, MAX_FEE + ud(1), MAX_UD60x18); - - // Set the protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - changePrank({ msgSender: users.sender }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_ProtocolFeeTooHigh.selector, protocolFee, MAX_FEE) - ); - createDefaultStream(); - } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) external whenNotDelegateCalled @@ -167,23 +137,22 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh { vm.assume(broker.account != address(0)); - broker.fee = _bound(broker.fee, MAX_FEE + ud(1), MAX_UD60x18); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_FEE)); + broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + ); createDefaultStreamWithBroker(broker); } struct Vars { uint256 actualNextStreamId; address actualNFTOwner; - uint256 actualProtocolRevenues; Lockup.Status actualStatus; Lockup.CreateAmounts createAmounts; uint256 expectedNextStreamId; address expectedNFTOwner; - uint256 expectedProtocolRevenues; Lockup.Status expectedStatus; bool isCancelable; bool isSettled; @@ -200,11 +169,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is /// - Start time in the future /// - Start time equal and not equal to the first tranche timestamp /// - Multiple values for the broker fee, including zero - /// - Multiple values for the protocol fee, including zero function testFuzz_CreateWithTimestamps( address funder, - LockupTranched.CreateWithTimestamps memory params, - UD60x18 protocolFee + LockupTranched.CreateWithTimestamps memory params ) external whenNotDelegateCalled @@ -217,34 +184,28 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum - givenProtocolFeeNotTooHigh whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 { vm.assume(funder != address(0) && params.recipient != address(0) && params.broker.account != address(0)); vm.assume(params.tranches.length != 0); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); - protocolFee = _bound(protocolFee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); params.transferable = true; // Fuzz the tranche timestamps. fuzzTrancheTimestamps(params.tranches, params.startTime); - // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the tranche amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: params.tranches, - protocolFee: protocolFee, brokerFee: params.broker.fee }); - // Set the fuzzed protocol fee. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: protocolFee }); - // Make the fuzzed funder the caller in the rest of this test. changePrank(funder); @@ -255,11 +216,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. - expectCallToTransferFrom({ - from: funder, - to: address(lockupTranched), - value: vars.createAmounts.deposit + vars.createAmounts.protocolFee - }); + expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -336,11 +293,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - // Assert that the protocol fee has been recorded. - vars.actualProtocolRevenues = lockupTranched.protocolRevenues(dai); - vars.expectedProtocolRevenues = vars.createAmounts.protocolFee; - assertEq(vars.actualProtocolRevenues, vars.expectedProtocolRevenues, "protocolRevenues"); - // Assert that the NFT has been minted. vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = params.recipient; diff --git a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 47a5b9650..31b8a325f 100644 --- a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -19,9 +19,6 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Fuzz_Test.setUp(); StreamedAmountOf_Integration_Shared_Test.setUp(); - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); } @@ -58,12 +55,8 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is fuzzTrancheTimestamps(tranches, defaults.START_TIME()); // Fuzz the tranche amounts. - (uint128 totalAmount,) = fuzzTranchedStreamAmounts({ - upperBound: MAX_UINT128, - tranches: tranches, - protocolFee: ZERO, - brokerFee: ZERO - }); + (uint128 totalAmount,) = + fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: ZERO }); // Bound the time jump. uint40 firstTrancheDuration = tranches[1].timestamp - tranches[0].timestamp; @@ -109,12 +102,8 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is fuzzTrancheTimestamps(tranches, defaults.START_TIME()); // Fuzz the tranche amounts. - (uint128 totalAmount,) = fuzzTranchedStreamAmounts({ - upperBound: MAX_UINT128, - tranches: tranches, - protocolFee: ZERO, - brokerFee: ZERO - }); + (uint128 totalAmount,) = + fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: ZERO }); // Bound the time warps. uint40 firstTrancheDuration = tranches[1].timestamp - tranches[0].timestamp; diff --git a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 6fed27a48..50f6367d2 100644 --- a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -20,9 +20,6 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Fuzz_Test.setUp(); WithdrawableAmountOf_Integration_Shared_Test.setUp(); - // Disable the protocol fee so that it doesn't interfere with the calculations. - changePrank({ msgSender: users.admin }); - comptroller.setProtocolFee({ asset: dai, newProtocolFee: ZERO }); changePrank({ msgSender: users.sender }); } diff --git a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol index 574f79390..3b1b3c53e 100644 --- a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol @@ -50,10 +50,6 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupDynamic_Integrati _; } - modifier givenProtocolFeeNotTooHigh() { - _; - } - modifier whenBrokerFeeNotTooHigh() { _; } diff --git a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol index df2734c6d..ebe9f366d 100644 --- a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol @@ -34,10 +34,6 @@ abstract contract CreateWithTimestamps_Integration_Shared_Test is LockupLinear_I _; } - modifier givenProtocolFeeNotTooHigh() { - _; - } - modifier whenBrokerFeeNotTooHigh() { _; } diff --git a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol index a5dede843..88ff66f17 100644 --- a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol @@ -50,10 +50,6 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupTranched_Integrat _; } - modifier givenProtocolFeeNotTooHigh() { - _; - } - modifier whenBrokerFeeNotTooHigh() { _; } diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 8fd00072c..fc6153371 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -3,23 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Base } from "src/interfaces/ISablierV2Base.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Broker } from "src/types/DataTypes.sol"; import { Base_Test } from "test/Base.t.sol"; /// @dev This contracts avoids duplicating test logic for {SablierV2LockupLinear} and {SablierV2LockupDynamic}; -/// both of these contracts inherit from {SablierV2Base} and {SablierV2Lockup}. +/// both of these contracts inherit from {SablierV2Lockup}. abstract contract Lockup_Integration_Shared_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev A test contract that is meant to be overridden by the implementing contract, which will be - /// either {SablierV2LockupLinear} or {SablierV2LockupDynamic}. - ISablierV2Base internal base; - /// @dev A test contract that is meant to be overridden by the implementing contract, which will be /// either {SablierV2LockupLinear} or {SablierV2LockupDynamic}. ISablierV2Lockup internal lockup; @@ -29,10 +24,6 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public virtual override { - // Set the default protocol fee. - comptroller.setProtocolFee({ asset: dai, newProtocolFee: defaults.PROTOCOL_FEE() }); - comptroller.setProtocolFee({ asset: IERC20(address(usdt)), newProtocolFee: defaults.PROTOCOL_FEE() }); - // Make the Sender the default caller in this test suite. changePrank({ msgSender: users.sender }); } diff --git a/test/invariant/Invariant.t.sol b/test/invariant/Invariant.t.sol index 283d28e17..c6a0f4325 100644 --- a/test/invariant/Invariant.t.sol +++ b/test/invariant/Invariant.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { StdInvariant } from "forge-std/src/StdInvariant.sol"; import { Base_Test } from "../Base.t.sol"; -import { ComptrollerHandler } from "./handlers/ComptrollerHandler.sol"; import { TimestampStore } from "./stores/TimestampStore.sol"; /// @notice Common logic needed by all invariant tests. @@ -13,7 +12,6 @@ abstract contract Invariant_Test is Base_Test, StdInvariant { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ComptrollerHandler internal comptrollerHandler; TimestampStore internal timestampStore; /*////////////////////////////////////////////////////////////////////////// @@ -34,21 +32,11 @@ abstract contract Invariant_Test is Base_Test, StdInvariant { // Deploy the handlers. timestampStore = new TimestampStore(); - comptrollerHandler = - new ComptrollerHandler({ asset_: dai, comptroller_: comptroller, timestampStore_: timestampStore }); - changePrank(users.admin); - comptroller.transferAdmin(address(comptrollerHandler)); // Label the handlers. - vm.label({ account: address(comptrollerHandler), newLabel: "ComptrollerHandler" }); vm.label({ account: address(timestampStore), newLabel: "TimestampStore" }); - // Target only the handlers for invariant testing (to avoid getting reverts). - targetContract(address(comptrollerHandler)); - // Prevent these contracts from being fuzzed as `msg.sender`. - excludeSender(address(comptroller)); - excludeSender(address(comptrollerHandler)); excludeSender(address(lockupDynamic)); excludeSender(address(lockupLinear)); excludeSender(address(timestampStore)); diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index ffe71ea59..9db2edcc4 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -40,7 +40,6 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { // solhint-disable max-line-length function invariant_ContractBalance() external useCurrentTimestamp { uint256 contractBalance = dai.balanceOf(address(lockup)); - uint256 protocolRevenues = lockup.protocolRevenues(dai); uint256 lastStreamId = lockupStore.lastStreamId(); uint256 depositedAmountsSum; @@ -55,8 +54,8 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { assertGte( contractBalance, - depositedAmountsSum + protocolRevenues - refundedAmountsSum - withdrawnAmountsSum, - unicode"Invariant violation: contract balances < Σ deposited amounts + protocol revenues - Σ refunded amounts - Σ withdrawn amounts" + depositedAmountsSum - refundedAmountsSum - withdrawnAmountsSum, + unicode"Invariant violation: contract balances < Σ deposited amounts - Σ refunded amounts - Σ withdrawn amounts" ); } diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index 415586a7e..cc7d75d29 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -34,7 +34,6 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { asset_: dai, timestampStore_: timestampStore, lockupStore_: lockupStore, - comptroller_: comptroller, lockupDynamic_: lockupDynamic }); diff --git a/test/invariant/LockupTranched.t.sol b/test/invariant/LockupTranched.t.sol index 27ed3f778..c57c3e177 100644 --- a/test/invariant/LockupTranched.t.sol +++ b/test/invariant/LockupTranched.t.sol @@ -34,7 +34,6 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { asset_: dai, timestampStore_: timestampStore, lockupStore_: lockupStore, - comptroller_: comptroller, lockupTranched_: lockupTranched }); diff --git a/test/invariant/handlers/ComptrollerHandler.sol b/test/invariant/handlers/ComptrollerHandler.sol deleted file mode 100644 index 061f8e5a7..000000000 --- a/test/invariant/handlers/ComptrollerHandler.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; - -import { TimestampStore } from "../stores/TimestampStore.sol"; -import { BaseHandler } from "./BaseHandler.sol"; - -/// @dev This contract and not {SablierV2Comptroller} is exposed to Foundry for invariant testing. The point is -/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. -contract ComptrollerHandler is BaseHandler { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierV2Comptroller public comptroller; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor( - IERC20 asset_, - TimestampStore timestampStore_, - ISablierV2Comptroller comptroller_ - ) - BaseHandler(asset_, timestampStore_) - { - comptroller = comptroller_; - } - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-COMPTROLLER - //////////////////////////////////////////////////////////////////////////*/ - - function setProtocolFee( - uint256 timeJumpSeed, - UD60x18 newProtocolFee - ) - external - instrument("setProtocolFee") - adjustTimestamp(timeJumpSeed) - { - newProtocolFee = _bound(newProtocolFee, 0, MAX_FEE); - comptroller.setProtocolFee(asset, newProtocolFee); - } -} diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 3c97d9cd8..44e4b8dec 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; import { LockupDynamic } from "src/types/DataTypes.sol"; @@ -19,7 +18,6 @@ contract LockupDynamicCreateHandler is BaseHandler { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2Comptroller public comptroller; ISablierV2LockupDynamic public lockupDynamic; LockupStore public lockupStore; @@ -31,13 +29,11 @@ contract LockupDynamicCreateHandler is BaseHandler { IERC20 asset_, TimestampStore timestampStore_, LockupStore lockupStore_, - ISablierV2Comptroller comptroller_, ISablierV2LockupDynamic lockupDynamic_ ) BaseHandler(asset_, timestampStore_) { lockupStore = lockupStore_; - comptroller = comptroller_; lockupDynamic = lockupDynamic_; } @@ -66,16 +62,15 @@ contract LockupDynamicCreateHandler is BaseHandler { } // Bound the broker fee. - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); // Fuzz the durations. fuzzSegmentDurations(params.segments); - // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the segment amounts and calculate the total amount. (params.totalAmount,) = fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: params.segments, - protocolFee: comptroller.protocolFees(asset), brokerFee: params.broker.fee }); @@ -113,17 +108,16 @@ contract LockupDynamicCreateHandler is BaseHandler { return; } - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); - // Fuzz the segment amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the segment amounts and calculate the total amount. (params.totalAmount,) = fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: params.segments, - protocolFee: comptroller.protocolFees(asset), brokerFee: params.broker.fee }); diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index 7ff5527e4..94dc6a034 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -135,22 +135,6 @@ abstract contract LockupHandler is BaseHandler { lockup.cancel(currentStreamId); } - function claimProtocolRevenues(uint256 timeJumpSeed) - external - instrument("claimProtocolRevenues") - adjustTimestamp(timeJumpSeed) - useAdmin - { - // Can claim revenues only if the protocol has revenues. - uint128 protocolRevenues = lockup.protocolRevenues(asset); - if (protocolRevenues == 0) { - return; - } - - // Claim the protocol revenues. - lockup.claimProtocolRevenues(asset); - } - function renounce( uint256 timeJumpSeed, uint256 streamIndexSeed diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index 5aab6bfa6..cc6b7b498 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -57,7 +57,7 @@ contract LockupLinearCreateHandler is BaseHandler { } // Bound the stream parameters. - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.durations.cliff = boundUint40(params.durations.cliff, 1 seconds, 2500 seconds); params.durations.total = boundUint40(params.durations.total, params.durations.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); @@ -93,7 +93,7 @@ contract LockupLinearCreateHandler is BaseHandler { } uint40 currentTime = getBlockTimestamp(); - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.range.start = boundUint40(params.range.start, 1, currentTime); params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/invariant/handlers/LockupTranchedCreateHandler.sol index faf3aa438..91a95740d 100644 --- a/test/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/invariant/handlers/LockupTranchedCreateHandler.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Comptroller } from "src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; import { LockupTranched } from "src/types/DataTypes.sol"; @@ -19,7 +18,6 @@ contract LockupTranchedCreateHandler is BaseHandler { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2Comptroller public comptroller; LockupStore public lockupStore; ISablierV2LockupTranched public lockupTranched; @@ -31,13 +29,11 @@ contract LockupTranchedCreateHandler is BaseHandler { IERC20 asset_, TimestampStore timestampStore_, LockupStore lockupStore_, - ISablierV2Comptroller comptroller_, ISablierV2LockupTranched lockupTranched_ ) BaseHandler(asset_, timestampStore_) { lockupStore = lockupStore_; - comptroller = comptroller_; lockupTranched = lockupTranched_; } @@ -66,16 +62,15 @@ contract LockupTranchedCreateHandler is BaseHandler { } // Bound the broker fee. - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); // Fuzz the durations. fuzzTrancheDurations(params.tranches); - // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the tranche amounts and calculate the total amount. (params.totalAmount,) = fuzzTranchedStreamAmounts({ upperBound: 1_000_000_000e18, tranches: params.tranches, - protocolFee: comptroller.protocolFees(asset), brokerFee: params.broker.fee }); @@ -113,17 +108,16 @@ contract LockupTranchedCreateHandler is BaseHandler { return; } - params.broker.fee = _bound(params.broker.fee, 0, MAX_FEE); + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); // Fuzz the tranche timestamps. fuzzTrancheTimestamps(params.tranches, params.startTime); - // Fuzz the tranche amounts and calculate the create amounts (total, deposit, protocol fee, and broker fee). + // Fuzz the tranche amounts and calculate the total amount. (params.totalAmount,) = fuzzTranchedStreamAmounts({ upperBound: 1_000_000_000e18, tranches: params.tranches, - protocolFee: comptroller.protocolFees(asset), brokerFee: params.broker.fee }); diff --git a/test/unit/concrete/comptroller/Comptroller.t.sol b/test/unit/concrete/comptroller/Comptroller.t.sol deleted file mode 100644 index e3899b8b4..000000000 --- a/test/unit/concrete/comptroller/Comptroller.t.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2Comptroller } from "../../../../src/SablierV2Comptroller.sol"; - -import { Base_Test } from "../../../Base.t.sol"; - -contract Comptroller_Unit_Concrete_Test is Base_Test { - function setUp() public virtual override { - Base_Test.setUp(); - deployConditionally(); - } - - /// @dev Conditionally deploys {SablierV2Comptroller} normally or from a source precompiled with `--via-ir`. - function deployConditionally() internal { - if (!isTestOptimizedProfile()) { - comptroller = new SablierV2Comptroller(users.admin); - } else { - comptroller = deployOptimizedComptroller(users.admin); - } - vm.label({ account: address(comptroller), newLabel: "SablierV2Comptroller" }); - } -} diff --git a/test/unit/concrete/comptroller/constructor.t.sol b/test/unit/concrete/comptroller/constructor.t.sol deleted file mode 100644 index 80d16c1d9..000000000 --- a/test/unit/concrete/comptroller/constructor.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2Comptroller } from "src/SablierV2Comptroller.sol"; - -import { Base_Test } from "../../../Base.t.sol"; - -contract Constructor_Comptroller_Unit_Concrete_Test is Base_Test { - function test_Constructor() external { - // Expect the relevant event to be emitted. - vm.expectEmit(); - emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); - - // Construct the contract. - SablierV2Comptroller constructedComptroller = new SablierV2Comptroller({ initialAdmin: users.admin }); - - // Assert that the admin has been initialized. - address actualAdmin = constructedComptroller.admin(); - address expectedAdmin = users.admin; - assertEq(actualAdmin, expectedAdmin, "admin"); - } -} diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index 20d4ff0ca..2beda673a 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -16,20 +16,10 @@ abstract contract Calculations { Defaults private defaults = new Defaults(); - /// @dev Calculates the deposit amount by calculating and subtracting the protocol fee amount and the - /// broker fee amount from the total amount. - function calculateDepositAmount( - uint128 totalAmount, - UD60x18 protocolFee, - UD60x18 brokerFee - ) - internal - pure - returns (uint128) - { - uint128 protocolFeeAmount = ud(totalAmount).mul(protocolFee).intoUint128(); + /// @dev Calculates the deposit amount by calculating and subtracting the broker fee amount from the total amount. + function calculateDepositAmount(uint128 totalAmount, UD60x18 brokerFee) internal pure returns (uint128) { uint128 brokerFeeAmount = ud(totalAmount).mul(brokerFee).intoUint128(); - return totalAmount - protocolFeeAmount - brokerFeeAmount; + return totalAmount - brokerFeeAmount; } /// @dev Helper function that replicates the logic of {SablierV2LockupLinear.streamedAmountOf}. diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index b65cfc8eb..a7c8564f4 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -5,7 +5,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; abstract contract Constants { uint40 internal constant MAY_1_2023 = 1_682_899_200; - UD60x18 internal constant MAX_FEE = UD60x18.wrap(0.1e18); // 10% + UD60x18 internal constant MAX_BROKER_FEE = UD60x18.wrap(0.1e18); // 10% uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 uint128 internal constant MAX_UINT128 = type(uint128).max; uint40 internal constant MAX_UINT40 = type(uint40).max; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 39ad671fc..10de17ebd 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -17,7 +17,7 @@ contract Defaults is Constants { //////////////////////////////////////////////////////////////////////////*/ UD60x18 public constant BROKER_FEE = UD60x18.wrap(0.003e18); // 0.3% - uint128 public constant BROKER_FEE_AMOUNT = 30.120481927710843373e18; // 0.3% of total amount + uint128 public constant BROKER_FEE_AMOUNT = 30.090270812437311935e18; // 0.3% of total amount uint128 public constant CLIFF_AMOUNT = 2500e18; uint40 public immutable CLIFF_TIME; uint40 public constant CLIFF_DURATION = 2500 seconds; @@ -25,12 +25,10 @@ contract Defaults is Constants { uint40 public immutable END_TIME; uint256 public constant MAX_COUNT = 500; uint40 public immutable MAX_SEGMENT_DURATION; - UD60x18 public constant PROTOCOL_FEE = UD60x18.wrap(0.001e18); // 0.1% - uint128 public constant PROTOCOL_FEE_AMOUNT = 10.040160642570281124e18; // 0.1% of total amount uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; uint256 public SEGMENT_COUNT; uint40 public immutable START_TIME; - uint128 public constant TOTAL_AMOUNT = 10_040.160642570281124497e18; // deposit / (1 - fee) + uint128 public constant TOTAL_AMOUNT = 10_030.090270812437311935e18; // deposit + broker fee uint40 public constant TOTAL_DURATION = 10_000 seconds; uint256 public TRANCHE_COUNT; uint128 public constant WITHDRAW_AMOUNT = 2600e18; @@ -82,11 +80,7 @@ contract Defaults is Constants { } function lockupCreateAmounts() public pure returns (Lockup.CreateAmounts memory) { - return Lockup.CreateAmounts({ - deposit: DEPOSIT_AMOUNT, - protocolFee: PROTOCOL_FEE_AMOUNT, - brokerFee: BROKER_FEE_AMOUNT - }); + return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } function lockupDynamicRange() public view returns (LockupDynamic.Range memory) { diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index da78d2267..cb7418f99 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -3,24 +3,15 @@ pragma solidity >=0.8.22 <0.9.0; import { StdCheats } from "forge-std/src/StdCheats.sol"; -import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; abstract contract DeployOptimized is StdCheats { - /// @dev Deploys {SablierV2Comptroller} from an optimized source compiled with `--via-ir`. - function deployOptimizedComptroller(address initialAdmin) internal returns (ISablierV2Comptroller) { - return ISablierV2Comptroller( - deployCode("out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json", abi.encode(initialAdmin)) - ); - } - /// @dev Deploys {SablierV2LockupDynamic} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupDynamic( address initialAdmin, - ISablierV2Comptroller comptroller_, ISablierV2NFTDescriptor nftDescriptor_, uint256 maxSegmentCount ) @@ -30,7 +21,7 @@ abstract contract DeployOptimized is StdCheats { return ISablierV2LockupDynamic( deployCode( "out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json", - abi.encode(initialAdmin, address(comptroller_), address(nftDescriptor_), maxSegmentCount) + abi.encode(initialAdmin, address(nftDescriptor_), maxSegmentCount) ) ); } @@ -38,7 +29,6 @@ abstract contract DeployOptimized is StdCheats { /// @dev Deploys {SablierV2LockupLinear} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupLinear( address initialAdmin, - ISablierV2Comptroller comptroller_, ISablierV2NFTDescriptor nftDescriptor_ ) internal @@ -47,7 +37,7 @@ abstract contract DeployOptimized is StdCheats { return ISablierV2LockupLinear( deployCode( "out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json", - abi.encode(initialAdmin, address(comptroller_), address(nftDescriptor_)) + abi.encode(initialAdmin, address(nftDescriptor_)) ) ); } @@ -55,7 +45,6 @@ abstract contract DeployOptimized is StdCheats { /// @dev Deploys {SablierV2LockupTranched} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupTranched( address initialAdmin, - ISablierV2Comptroller comptroller_, ISablierV2NFTDescriptor nftDescriptor_, uint256 maxTrancheCount ) @@ -65,7 +54,7 @@ abstract contract DeployOptimized is StdCheats { return ISablierV2LockupTranched( deployCode( "out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json", - abi.encode(initialAdmin, address(comptroller_), address(nftDescriptor_), maxTrancheCount) + abi.encode(initialAdmin, address(nftDescriptor_), maxTrancheCount) ) ); } @@ -78,22 +67,19 @@ abstract contract DeployOptimized is StdCheats { function deployOptimizedCore( address initialAdmin, - uint256 maxSegmentCount, - uint256 maxTrancheCount + uint256 maxCount ) internal returns ( - ISablierV2Comptroller comptroller_, ISablierV2LockupDynamic lockupDynamic_, ISablierV2LockupLinear lockupLinear_, ISablierV2LockupTranched lockupTranched_, ISablierV2NFTDescriptor nftDescriptor_ ) { - comptroller_ = deployOptimizedComptroller(initialAdmin); nftDescriptor_ = deployOptimizedNFTDescriptor(); - lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, comptroller_, nftDescriptor_, maxSegmentCount); - lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, comptroller_, nftDescriptor_); - lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, comptroller_, nftDescriptor_, maxTrancheCount); + lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxCount); + lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, nftDescriptor_); + lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxCount); } } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 314f99ea6..aeaf08220 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -2,9 +2,7 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; @@ -30,22 +28,6 @@ abstract contract Events { event TransferAdmin(address indexed oldAdmin, address indexed newAdmin); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-BASE - //////////////////////////////////////////////////////////////////////////*/ - - event ClaimProtocolRevenues(address indexed admin, IERC20 indexed asset, uint128 protocolRevenues); - - event SetComptroller( - address indexed admin, ISablierV2Comptroller oldComptroller, ISablierV2Comptroller newComptroller - ); - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-COMPTROLLER - //////////////////////////////////////////////////////////////////////////*/ - - event SetProtocolFee(address indexed admin, IERC20 indexed asset, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); - /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index 8528f743f..a4183491f 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -25,12 +25,8 @@ abstract contract Fuzzers is Constants, Utils { view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { - (totalAmount, createAmounts) = fuzzDynamicStreamAmounts({ - upperBound: MAX_UINT128, - segments: segments, - protocolFee: defaults.PROTOCOL_FEE(), - brokerFee: defaults.BROKER_FEE() - }); + (totalAmount, createAmounts) = + fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: defaults.BROKER_FEE() }); } /// @dev Just like {fuzzDynamicStreamAmounts} but with defaults. @@ -43,7 +39,6 @@ abstract contract Fuzzers is Constants, Utils { (totalAmount, createAmounts) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segmentsWithTimestamps, - protocolFee: defaults.PROTOCOL_FEE(), brokerFee: defaults.BROKER_FEE() }); for (uint256 i = 0; i < segmentsWithTimestamps.length; ++i) { @@ -51,12 +46,10 @@ abstract contract Fuzzers is Constants, Utils { } } - /// @dev Fuzzes the segment amounts and calculates the create amounts (total, deposit, protocol fee, and broker - /// fee). + /// @dev Fuzzes the segment amounts and calculate the total and create amounts (deposit and broker fee). function fuzzDynamicStreamAmounts( uint128 upperBound, LockupDynamic.SegmentWithDuration[] memory segments, - UD60x18 protocolFee, UD60x18 brokerFee ) internal @@ -64,19 +57,16 @@ abstract contract Fuzzers is Constants, Utils { returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { LockupDynamic.Segment[] memory segmentsWithTimestamps = getSegmentsWithTimestamps(segments); - (totalAmount, createAmounts) = - fuzzDynamicStreamAmounts(upperBound, segmentsWithTimestamps, protocolFee, brokerFee); + (totalAmount, createAmounts) = fuzzDynamicStreamAmounts(upperBound, segmentsWithTimestamps, brokerFee); for (uint256 i = 0; i < segmentsWithTimestamps.length; ++i) { segments[i].amount = segmentsWithTimestamps[i].amount; } } - /// @dev Fuzzes the segment amounts and calculates the create amounts (total, deposit, protocol fee and broker - /// fee). + /// @dev Fuzzes the segment amounts and calculate the total and create amounts (deposit and broker fee). function fuzzDynamicStreamAmounts( uint128 upperBound, LockupDynamic.Segment[] memory segments, - UD60x18 protocolFee, UD60x18 brokerFee ) internal @@ -102,19 +92,17 @@ abstract contract Fuzzers is Constants, Utils { // must equal the deposit amount) using this formula: // // $$ - // total = \frac{deposit}{1e18 - protocolFee - brokerFee} + // total = \frac{deposit}{1e18 - brokerFee} // $$ - totalAmount = ud(estimatedDepositAmount).div(ud(uUNIT - protocolFee.intoUint256() - brokerFee.intoUint256())) - .intoUint128(); + totalAmount = ud(estimatedDepositAmount).div(ud(uUNIT - brokerFee.intoUint256())).intoUint128(); - // Calculate the fee amounts. - createAmounts.protocolFee = ud(totalAmount).mul(protocolFee).intoUint128(); + // Calculate the broker fee amount. createAmounts.brokerFee = ud(totalAmount).mul(brokerFee).intoUint128(); // Here, we account for rounding errors and adjust the estimated deposit amount and the segments. We know // that the estimated deposit amount is not greater than the adjusted deposit amount below, because the inverse - // of {Helpers.checkAndCalculateFees} over-expresses the weight of the fees. - createAmounts.deposit = totalAmount - createAmounts.protocolFee - createAmounts.brokerFee; + // of {Helpers.checkAndCalculateBrokerFee} over-expresses the weight of the broker fee. + createAmounts.deposit = totalAmount - createAmounts.brokerFee; segments[segments.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); } @@ -172,12 +160,8 @@ abstract contract Fuzzers is Constants, Utils { view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { - (totalAmount, createAmounts) = fuzzTranchedStreamAmounts({ - upperBound: MAX_UINT128, - tranches: tranches, - protocolFee: defaults.PROTOCOL_FEE(), - brokerFee: defaults.BROKER_FEE() - }); + (totalAmount, createAmounts) = + fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: defaults.BROKER_FEE() }); } /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. @@ -190,7 +174,6 @@ abstract contract Fuzzers is Constants, Utils { (totalAmount, createAmounts) = fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranchesWithTimestamps, - protocolFee: defaults.PROTOCOL_FEE(), brokerFee: defaults.BROKER_FEE() }); for (uint256 i = 0; i < tranchesWithTimestamps.length; ++i) { @@ -198,12 +181,10 @@ abstract contract Fuzzers is Constants, Utils { } } - /// @dev Fuzzes the tranche amounts and calculates the create amounts (total, deposit, protocol fee, and broker - /// fee). + /// @dev Fuzzes the tranche amounts and calculates the total and create amounts (deposit and broker fee). function fuzzTranchedStreamAmounts( uint128 upperBound, LockupTranched.TrancheWithDuration[] memory tranches, - UD60x18 protocolFee, UD60x18 brokerFee ) internal @@ -211,19 +192,16 @@ abstract contract Fuzzers is Constants, Utils { returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { LockupTranched.Tranche[] memory tranchesWithTimestamps = getTranchesWithTimestamps(tranches); - (totalAmount, createAmounts) = - fuzzTranchedStreamAmounts(upperBound, tranchesWithTimestamps, protocolFee, brokerFee); + (totalAmount, createAmounts) = fuzzTranchedStreamAmounts(upperBound, tranchesWithTimestamps, brokerFee); for (uint256 i = 0; i < tranchesWithTimestamps.length; ++i) { tranches[i].amount = tranchesWithTimestamps[i].amount; } } - /// @dev Fuzzes the tranche amounts and calculates the create amounts (total, deposit, protocol fee and broker - /// fee). + /// @dev Fuzzes the tranche amounts and calculates the total and create amounts (deposit and broker fee). function fuzzTranchedStreamAmounts( uint128 upperBound, LockupTranched.Tranche[] memory tranches, - UD60x18 protocolFee, UD60x18 brokerFee ) internal @@ -249,19 +227,17 @@ abstract contract Fuzzers is Constants, Utils { // must equal the deposit amount) using this formula: // // $$ - // total = \frac{deposit}{1e18 - protocolFee - brokerFee} + // total = \frac{deposit}{1e18 - brokerFee} // $$ - totalAmount = ud(estimatedDepositAmount).div(ud(uUNIT - protocolFee.intoUint256() - brokerFee.intoUint256())) - .intoUint128(); + totalAmount = ud(estimatedDepositAmount).div(ud(uUNIT - brokerFee.intoUint256())).intoUint128(); - // Calculate the fee amounts. - createAmounts.protocolFee = ud(totalAmount).mul(protocolFee).intoUint128(); + // Calculate the broker fee amount. createAmounts.brokerFee = ud(totalAmount).mul(brokerFee).intoUint128(); // Here, we account for rounding errors and adjust the estimated deposit amount and the tranches. We know // that the estimated deposit amount is not greater than the adjusted deposit amount below, because the inverse - // of {Helpers.checkAndCalculateFees} over-expresses the weight of the fees. - createAmounts.deposit = totalAmount - createAmounts.protocolFee - createAmounts.brokerFee; + // of {Helpers.checkAndCalculateBrokerFee} over-expresses the weight of the broker fee. + createAmounts.deposit = totalAmount - createAmounts.brokerFee; tranches[tranches.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); } diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 815c6d8f1..76c26e591 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -2,7 +2,6 @@ // solhint-disable max-line-length,no-inline-assembly,reason-string pragma solidity >=0.8.22; -import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; @@ -25,8 +24,6 @@ contract Precompiles { BYTECODES //////////////////////////////////////////////////////////////////////////*/ - bytes public constant BYTECODE_COMPTROLLER = - hex"60803461009857601f6102d538819003918201601f19168301916001600160401b0383118484101761009d5780849260209460405283398101031261009857516001600160a01b0381169081900361009857600080546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361022190816100b48239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040818152600436101561001457600080fd5b600091823560e01c90816375829def1461014c57508063b5b3ca2c146100ac578063dcf844a7146100765763f851a4401461004e57600080fd5b346100725781600319360112610072576001600160a01b0360209254169051908152f35b5080fd5b503461007257602036600319011261007257806020926001600160a01b0361009c6101f9565b1681526001845220549051908152f35b50346100725780600319360112610072576100c56101f9565b602435906001600160a01b0390818554163381036101245750907f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d9116928385526001602052808520928084549455815193845260208401523392a380f35b84516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b83903461007257602036600319011261007257600435906001600160a01b03908183168093036101f55783549182163381036101d25750507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6331b339a960e21b82526001600160a01b03166004820152336024820152604490fd5b8380fd5b600435906001600160a01b038216820361020f57565b600080fdfea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = hex"60c0346200046e57601f62005f8a38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615af6908162000494823960805181613d2b015260a051818181610e350152613e4c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a714612a185750806306fdde031461291b578063081812fc146128fd578063095ea7b3146127f65780631400ecec146127505780631c1cdd4c146126ea5780631e99d569146126cc57806323b872dd146126b557806331df3d48146125b257806339a73c031461256f57806340e58ee514612277578063425d30dd1461222157806342842e0e146121d057806342966c6814611fbd5780634426757014611f965780634857501f14611f1c5780634869e12d14611edf5780634cc55e1114611de457806354c0229214611b485780635fe3b56714611b215780636352211e14611af25780636d0cee7514611af257806370a0823114611a7e57806375829def146119e45780637cad6cd1146118e65780637de6b1db146116c95780638659c27014611379578063894e9a0d14610ff35780638bad38dd14610f485780638f69b99314610ead5780639067b67714610e585780639188ec8414610e1d57806395d89b4114610d09578063a22cb46514610c4b578063a6202bf214610b43578063a80fc07114610aec578063ad35efd414610a73578063b256456914610a1d578063b637b865146109be578063b88d4fde14610935578063b8a3be66146108ff578063b971302a146108ab578063bc063e1a14610888578063bc2be1be14610833578063c156a11d146106dd578063c87b56dd146105c9578063cc364f481461052d578063d4dbd20b146104d6578063d511609f14610485578063d975dfed14610437578063e985e9c5146103e0578063ea5ead19146103b2578063eac8f5b81461035b578063f590c176146102f6578063f851a440146102cf5763fdd46d601461028957600080fd5b346102ca5760603660031901126102ca576102a2612b44565b604435906001600160801b03821682036102ca576102c8926102c2613d21565b3561371c565b005b600080fd5b346102ca5760003660031901126102ca5760206001600160a01b0360005416604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360016040600020015416604051908152f35b50346102ca5760403660031901126102ca576102c890356103d1612b44565b6103da8261467a565b9161337a565b346102ca5760403660031901126102ca576103f9612b2e565b610401612b44565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760206104748361467a565b6001600160801b0360405191168152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060026040600020015460801c604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360036040600020015416604051908152f35b50346102ca5760203660031901126102ca578035906000602060405161055281612c94565b828152015281600052600b60205260ff60016040600020015460a81c16156103465750600052600b6020526040806000205464ffffffffff82519161059683612c94565b818160a01c16835260c81c1660208201526105c7825180926020908164ffffffffff91828151168552015116910152565bf35b50346102ca576020806003193601126102ca57600082356105e981613aa2565b5060446001600160a01b03600a54169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106d157600092610658575b50610654604051928284938452830190612b09565b0390f35b9091503d806000833e61066b8183612ce1565b81019082818303126102ca5780519067ffffffffffffffff82116102ca570181601f820112156102ca5780516106a081612d03565b926106ae6040519485612ce1565b8184528482840101116102ca576106ca91848085019101612ae6565b903861063f565b6040513d6000823e3d90fd5b50346102ca5760403660031901126102ca578035906106fa612b44565b91610703613d21565b80600052600b60205260ff60016040600020015460a81c161561081d578060005260056020526001600160a01b038060406000205416938433036107fa5761074a8361467a565b6001600160801b0381166107e9575b50818116156107d1578261076c91613bdc565b9081168061078b576024848460405191637e27328960e01b8352820152fd5b840361079357005b6107cd916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107f490868561337a565b38610759565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102ca5760003660031901126102ca57602060405167016345785d8a00008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360406000205416604051908152f35b50346102ca5760203660031901126102ca5735600052600b602052602060ff60016040600020015460a81c166040519015158152f35b50346102ca5760803660031901126102ca5761094f612b2e565b610957612b44565b906064359267ffffffffffffffff84116102ca57366023850112156102ca578301359161098383612d03565b926109916040519485612ce1565b80845236602482870101116102ca5760208160009260246102c89801838801378501015260443591613206565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600c602052610654610a096040600020613176565b604051918291602083526020830190612bd4565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460b01c166040519015158152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610aad90613b55565b604051906005811015610ac257602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360026040600020015416604051908152f35b50346102ca5760203660031901126102ca57610b5d612b2e565b906001600160a01b038060005416338103610c1c57508216918260005260026020526001600160801b0360406000205416918215610bec575081610bbe9184600052600260205260406000206001600160801b0319815416905533906145ee565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b60249084604051917f8410168c000000000000000000000000000000000000000000000000000000008352820152fd5b604080516331b339a960e21b81526001600160a01b039092169382019384523360208501529092839250010390fd5b50346102ca5760403660031901126102ca57610c65612b2e565b602435908115158092036102ca576001600160a01b0316918215610cd95750336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760003660031901126102ca576040519060009080549160018360011c9260018516948515610e13575b6020958686108114610dfe57858852879493929187908215610ddc575050600114610d80575b5050610d6c92500383612ce1565b610654604051928284938452830190612b09565b8592506000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610dc4575050610d6c93508201013880610d5e565b80548389018501528794508693909201918101610dac565b9250935050610d6c94915060ff191682840152151560051b8201013880610d5e565b602283634e487b7160e01b6000525260246000fd5b93607f1693610d38565b346102ca5760003660031901126102ca5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610ee790613b55565b9060058210159081610f255760028314918215610f3a575b8215610f13575b6020836040519015158152f35b909150610f2557602091143880610f06565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610eff565b50346102ca5760203660031901126102ca5780356001600160a01b03918282168092036102ca578260005416338103610fc557505060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b604080516331b339a960e21b81526001600160a01b0390921692820192835233602084015290918291010390fd5b50346102ca5760203660031901126102ca57604051610160810181811067ffffffffffffffff821117611364576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e0820152600061010082015261106e613123565b61012082015201528035600052600b60205260ff60016040600020015460a81c161561134c578035600052600b60205260406000209061113e6002604051936110b685612cc4565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613142565b61012083015261114e8135613b55565b60058110156113375760021461132b575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600c602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761131657506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161123990613176565b82820152610654604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130261012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190612bd4565b604190634e487b7160e01b6000525260246000fd5b6000606083015261115f565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b50346102ca57602090816003193601126102ca57803567ffffffffffffffff81116102ca576113ab9036908301612ba3565b90926113b5613d21565b6000915b8083106113c257005b6113cd8382876130c8565b35926113d7613d21565b83600052600b9081845260ff9160019280846040600020015460a81c16156116b357866000528186526040600020818582015460a01c1660001461142c576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c61169c5761145c81600052600b6020526001600160a01b0360406000205416331490565b1561167a5761146a81613add565b92816000528088526114826002604060002001613142565b936001600160801b03938486511685831610156116635783600052828a5260406000205460f01c161561164c5780848a6114c26114cc94838a5116612d57565b9701511690612d57565b9382600052818952886040600020977f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50895497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a16178b5560038882169b8c15611633575b0197851697886001600160801b03198254161790556001600160a01b038099169889936005865281604060002054169788965260406000200154169461157c8985886145ee565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6115df575b50505050600191500191906113b9565b803b156102ca578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611624575b8080806115cf565b61162d90612cb0565b3861161c565b848101600160a01b60ff60a01b19825416179055611535565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b50346102ca57602090816003193601126102ca5780356116e7613d21565b80600052600b835260ff60016040600020015460a81c161561081d5761170c81613b55565b926005841015610ac257838303611734576024838360405191634a5541ef60e01b8352820152fd5b6003840361175357602483836040519163fe19f19f60e01b8352820152fd5b90600284146118cf5761177c81600052600b6020526001600160a01b0360406000205416331490565b156118ad5780600052600b825260ff60406000205460f01c16156118965780600052600b8252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600583526001600160a01b036040600020541693843b611822575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b156102ca578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611887575b806117f6565b61189090612cb0565b83611881565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b50346102ca5760203660031901126102ca5780356001600160a01b03908181168091036102ca5781600054163381036119b85750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101919082116119a3577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576119fe612b2e565b600054906001600160a01b0390818316338103611a5257506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576001600160a01b03611aa0612b2e565b16908115611ac1575060005260066020526020604060002054604051908152f35b6024906000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760203660031901126102ca57611b1060209135613aa2565b6001600160a01b0360405191168152f35b346102ca5760003660031901126102ca5760206001600160a01b0360015416604051908152f35b50346102ca576020906003199082823601126102ca5780359167ffffffffffffffff908184116102ca57610120843603918201126102ca57611b88613d21565b60c484013590602219018112156102ca57830182810135908282116102ca5760240160608202360381136102ca57611bc1913691612ff9565b9283519281611bcf85612fe1565b94611bdd6040519687612ce1565b808652601f19611bec82612fe1565b018860005b828110611dc65750505064ffffffffff90814216956001600160801b039889611c1982613d7d565b515116828c611c2784613d7d565b5101511685806040611c3886613d7d565b510151168b01169060405192611c4d84612c78565b83528d8301526040820152611c618a613d7d565b52611c6b89613d7d565b5060019360015b8c8b8d878410611d3757908c8a611c8a818e01613102565b92611c9760248301613102565b92611ca4604484016130ee565b946064840135946001600160a01b03958681168091036102ca57611d2f98611cef98611d2498611cd660848a01613116565b9481611ce460a48c01613116565b976040519d8e612c45565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613099565b610100820152613d9e565b604051908152f35b8899509084806040611d748a87611d648c9d9e9f9b9c99988b90611d5b828d613d8a565b5151169a613d8a565b5101511694600019890190613d8a565b51015116816040611d85888c613d8a565b5101511601169160405193611d9985612c78565b84528301526040820152611dad828d613d8a565b52611db8818c613d8a565b500190879594939291611c72565b9091929350611dd3613123565b82828a010152019088859392611bf1565b50346102ca5760403660031901126102ca5767ffffffffffffffff9080358281116102ca57611e169036908301612ba3565b926024359081116102ca57611e2e9036908401612ba3565b919092611e39613d21565b828503611ea9575060005b848110611e4d57005b80611ea3611e5e60019388866130c8565b35611e6a8389876130c8565b3560005260056020526001600160a01b0360406000205416611e95611e9085898b6130c8565b6130ee565b91611e9e613d21565b61371c565b01611e44565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657602061047483614b1c565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657600090611f5a83613b55565b906005821015610f255750600203611f7a575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611f6d565b346102ca5760003660031901126102ca5760206001600160a01b03600a5416604051908152f35b50346102ca57602090816003193601126102ca57803591611fdc613d21565b82600052600b815260ff60016040600020015460a81c16156121ba5782600052600b815260ff60016040600020015460a01c161561218a5761201d83614585565b156121665782600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c1615908161215c575b5080612154575b61213d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526005835260406000205416918215928315612102575b856000526005825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a16120ec57005b60249160405191637e27328960e01b8352820152fd5b61212386600052600760205260406000206001600160a01b03198154169055565b80600052600682526040600020600019815401905561209c565b6024838560405191630da9b01360e01b8352820152fd5b50600061205c565b9050151538612055565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b50346102ca576121df36612b6e565b90604051926020840184811067ffffffffffffffff82111761220c576102c8955060405260008452613206565b604186634e487b7160e01b6000525260246000fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460a01c166040519015158152f35b50346102ca57602090816003193601126102ca578035612295613d21565b80600052600b80845260ff60016040600020015460a81c16156125595781600052808452604060002060ff600182015460a01c166000146122e7576024848460405191634a5541ef60e01b8352820152fd5b5460f81c6125425761230f82600052600b6020526001600160a01b0360406000205416331490565b156125205761231d82613add565b92826000528185526123356002604060002001613142565b936001600160801b0390818651168282161015612509578460005283875260ff60406000205460f01c16156124f257866123c482847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a6123ba7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612d57565b9a01511690612d57565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156124d8575b0195811695866001600160801b03198254161790556001600160a01b03809a169a8b91600586528a6124828d604060002054169d8e96895260016040600020015416966124588b878a6145ee565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61249457005b843b156102ca576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16124cf57005b6102c890612cb0565b60018101600160a01b60ff60a01b1982541617905561240a565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b346102ca5760203660031901126102ca576001600160a01b03612590612b2e565b16600052600260205260206001600160801b0360406000205416604051908152f35b50346102ca57600319906020368301126102ca5780359167ffffffffffffffff908184116102ca576101409084360301126102ca576125ef613d21565b604051906125fc82612c45565b612607848401612b5a565b825261261560248501612b5a565b602083015261262660448501612d1f565b604083015261263760648501612b5a565b606083015261264860848501612c38565b608083015261265960a48501612c38565b60a083015261266a60c48501612fcf565b60c083015260e48401359081116102ca57830191366023840112156102ca576020936126a5611d2492611d2f95602436928201359101612ff9565b60e0840152610104369101613099565b346102ca576102c86126c636612b6e565b91612d86565b346102ca5760003660031901126102ca576020600954604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad75761272490613b55565b906005821015610f255760208215838115612745575b506040519015158152f35b60019150148261273a565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760208260009080600052600b8352604060002060ff815460f01c16806127e4575b6127bb575b50506001600160801b0360405191168152f35b6127dd92506001600160801b0360026127d79201541691613add565b90612d57565b82806127a8565b5060ff600182015460a01c16156127a3565b50346102ca5760403660031901126102ca57612810612b2e565b906024359061281e82613aa2565b90331515806128ea575b806128bc575b61288b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260076020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600860205260406000203360005260205260ff604060002054161561282e565b50336001600160a01b0383161415612828565b50346102ca5760203660031901126102ca57611b1060209135612d33565b50346102ca5760003660031901126102ca576040519060006003549060018260011c92600181168015612a0e575b60209586861082146129f9575084875286939291869082156129d957505060011461297c575b50610d6c92500383612ce1565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106129c1575050610d6c93508201013861296f565b805483890185015287945086939092019181016129aa565b60ff191685820152610d6c95151560051b850101925038915061296f9050565b602290634e487b7160e01b6000525260246000fd5b93607f1693612949565b82346102ca5760203660031901126102ca5735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102ca57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612abc575b8115612a92575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612a8b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612a84565b60005b838110612af95750506000910152565b8181015183820152602001612ae9565b90602091612b2281518092818552858086019101612ae6565b601f01601f1916010190565b600435906001600160a01b03821682036102ca57565b602435906001600160a01b03821682036102ca57565b35906001600160a01b03821682036102ca57565b60609060031901126102ca576001600160a01b039060043582811681036102ca579160243590811681036102ca579060443590565b9181601f840112156102ca5782359167ffffffffffffffff83116102ca576020808501948460051b0101116102ca57565b90815180825260208080930193019160005b828110612bf4575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612be6565b359081151582036102ca57565b610120810190811067ffffffffffffffff821117612c6257604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612c6257604052565b6040810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257604052565b610140810190811067ffffffffffffffff821117612c6257604052565b90601f8019910116810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257601f01601f191660200190565b35906001600160801b03821682036102ca57565b612d3c81613aa2565b5060005260076020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612d7057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612fb75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c16159081612fad575b5080612fa5575b612f8e578685526005815282848620541694873315159384612ede575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612ea6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612e785750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612ec782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055612e14565b91929380915090612f4d575b15612ef85790878392612deb565b848887612f15576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612f72575b80612eea5750878252600783523384868420541614612eea565b5085825260088352848220338352835260ff8583205416612f58565b602487855190630da9b01360e01b82526004820152fd5b506001612dce565b9050151538612dc7565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff821682036102ca57565b67ffffffffffffffff8111612c625760051b60200190565b92919261300582612fe1565b6040946130156040519283612ce1565b819584835260208093019160608096028501948186116102ca57925b8584106130415750505050505050565b86848303126102ca5782519061305682612c78565b61305f85612d1f565b8252858501359067ffffffffffffffff821682036102ca57828792838b95015261308a868801612fcf565b86820152815201930192613031565b91908260409103126102ca576040516130b181612c94565b60208082946130bf81612b5a565b84520135910152565b91908110156130d85760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102ca5790565b356001600160a01b03811681036102ca5790565b3580151581036102ca5790565b6040519061313082612c78565b60006040838281528260208201520152565b9060405161314f81612c78565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b90815461318281612fe1565b926040936131936040519182612ce1565b82815280946020809201926000526020600020906000935b8585106131ba57505050505050565b600184819284516131ca81612c78565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c16868201528152019301940193916131ab565b9190613213828285612d86565b803b613220575b50505050565b61327c6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612b09565b03906020816000938185885af190829082613312575b50506132c957826132a161464a565b80519190826132c25760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036132fa57503880808061321a565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613372575b8161332f60209383612ce1565b8101031261336e5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361336b5750903880613292565b80fd5b5080fd5b3d9150613322565b92919092613386613d21565b600093818552600b9260209380855260409260ff6001858a20015460a81c16156137065784885281865260ff6001858a20015460a01c166136ef576001600160a01b03918282169283156136df576001600160801b03938486169182156136c857888c5260058a5280888d2054169384831415806136b8575b6136955761340c8a61467a565b878116851161366457508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061343d916146a2565b878752838652828720600201908282549160801b6001600160801b031916911617815561346990613142565b90808683015116918184818351169201511661348491612d57565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d96613637575b878252855220015416946134c78189886145ee565b8a51908152a4803314158061362d575b6135c8575b8233141590816135bd575b816135b2575b50613521575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156135ae578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af161359f575b8594816134f3565b6135a890612cb0565b38613597565b8780fd5b9050821415386134ed565b833b151591506134e7565b803b15613629578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af161361a575b506134dc565b61362390612cb0565b38613614565b8880fd5b50803b15156134d7565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134b2565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506136c28a614585565b156133ff565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b92919092600093818552600b9060209382855260409260ff6001858a20015460a81c1615613706578785815281875260ff6001868320015460a01c16613a8b576001600160a01b0390818516928315613a7b576001600160801b0393848616918215613a645789845260058b52848985205416948583141580613a54575b613a31576137c18b838e6137ad83614b1c565b9289525260028c8820015460801c90612d57565b8781168511613a005750908b8b928387528282528b808820998b838c54169b6002015460801c906137f1916146a2565b868a52858552828a20600201908282549160801b6001600160801b031916911617815561381d90613142565b8180868301511693818351169201511661383691612d57565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936139d2575b848852825260018c88200154169461387a818c886145ee565b8b51908152a481331415806139c8575b613962575b50813314159081613957575b8161394c575b506138d4575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613948578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613930575b80806134f3565b61393a8691612cb0565b6139445784613929565b8480fd5b8280fd5b9050811415386138a1565b823b1515915061389b565b813b1561336b578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16139b4575b5061388f565b6139c091929a50612cb0565b9738806139ae565b50813b151561388a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613861565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b50613a5e8b614585565b1561379a565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260056020526001600160a01b0360406000205416908115613ac5575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c161015613b4b5760c81c161115613b395750600c602052600160406000205411600014613b3057613b2d9061478e565b90565b613b2d906146bd565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c16600014613b7c575050600490565b805460f81c613bd5575460a01c64ffffffffff164210613bcf57613b9f81613add565b90600052600b6020526001600160801b038060026040600020015416911610600014613bca57600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613d17575b5080613d0c575b613cf5579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613cbd575b169283613ca7575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613c83565b613cde86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613c7b565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c1a565b9050151538613c13565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613d5357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b8051156130d85760200190565b80518210156130d85760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106d157600090614551575b613e2091506001600160801b0360408501511690602061010086015101519161496e565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452757815180156144fd577f000000000000000000000000000000000000000000000000000000000000000081116144cc575064ffffffffff6040613e8384613d7d565b510151168110156144755750600090819082815184905b8082106143e4575050505064ffffffffff421664ffffffffff82168110156143a45750506001600160801b031680820361436d5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000604061402d8951996000198b0190613d8a565b51015160c81b169560f01b16911617171717845560005b81811061429b575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b036020830151168015612fb7576140cf866001600160a01b0392613bdc565b1661426a576141046001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614aad565b6001600160801b036040820151168061423a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6141f76001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661422f61420f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a38c612c94565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190612bd4565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b614264906001600160a01b036060850151166001600160a01b036101008601515116903390614aad565b38614118565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906142b88160e0870151613d8a565b51825468010000000000000000811015612c6257600181018085558110156130d857600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501614044565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614408906001600160801b036143ff8588613d8a565b515116906146a2565b9364ffffffffff80604061441c8685613d8a565b5101511694168085111561443857506001849301909291613e9a565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061448684613d7d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161457d575b8161456b60209383612ce1565b810103126102ca57613e209051613dfc565b3d915061455e565b60009080825260056020526001600160a01b0380604084205416928333149384156145ca575b505082156145b857505090565b9091506145c53392612d33565b161490565b60ff92945090604091815260086020528181203382526020522054169138806145ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261464891614643606483612ce1565b614b97565b565b3d15614675573d9061465b82612d03565b916146696040519384612ce1565b82523d6000602084013e565b606090565b613b2d9061468781614b1c565b90600052600b60205260026040600020015460801c90612d57565b9190916001600160801b0380809416911601918211612d7057565b64ffffffffff6146f2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614c33565b91808252600c6020526040822080541561477a5790829167ffffffffffffffff935261474c6020832054828452600b6020526147476001600160801b03968760026040882001541696879360801c1690614d23565b614d91565b92831361476257505061475e90614e7b565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff8042166000838152600b602052604091828220908351916147b483612cc4565b80549661012061483a60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201613142565b94019384528452600c602052614851858520613176565b918496808761485f86613d7d565b5101511692828288955b16106149385750916148ed614747928488816148f298976001600160801b039e8f614894898c613d8a565b5151169d8e9a67ffffffffffffffff60206148af8c84613d8a565b510151169984836148c08385613d8a565b510151169650801561492c576148dc9293506000190190613d8a565b5101511680925b0316920316614c33565b614d23565b92831361490b5750506149058391614e7b565b16011690565b5160200151929392831692841683101591506149279050575090565b905090565b505050511680926148e3565b8093986001600160801b03908161494f8c89613d8a565b51511601169801928282808a614965888a613d8a565b51015116614869565b909291614979613123565b936001600160801b0392838116918215614a855767016345785d8a0000808211614a4e57808511614a1757506149c3856149b48193866159a7565b169460208901958652846159a7565b1691846149da6040890194808652828751166146a2565b161015614a01576149f38491826149fc95511690612d57565b91511690612d57565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614a9881612c78565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612c625761464892604052614b97565b80600052600b602052614b356002604060002001613142565b81600052600b602052604060002060ff600182015460a01c16600014614b6857506001600160801b039150602001511690565b5460f81c614b7a5750613b2d90613add565b613b2d91506001600160801b036040818351169201511690612d57565b6001600160a01b031690614bc2600080836020829551910182875af1614bbb61464a565b9084615a56565b908151918215159283614c0b575b505050614bda5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261336e57602001519081159182150361336b5750388080614bd0565b600160ff1b808214908115614d19575b50614cef576000811215614ce657614c6c816000035b6000841215614cdf578360000390614eb7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614ca85760001991181315614ca25790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614eb7565b614c6c81614c59565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c43565b80614d3e5750614d3957670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614d8b575080614d63575050670de0b6b3a764000090565b670de0b6b3a76400008114614d8757614d8290614747613b2d93614fb1565b6150f3565b5090565b91505090565b600160ff1b808214908115614e71575b50614e47576000811215614e3e57614dca816000035b6000841215614e375783600003906159a7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614e005760001991181315614ca25790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906159a7565b614dca81614db7565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614da1565b60008112614e865790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614f735782851015614f3757908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614f81570490565b634e487b7160e01b600052601260045260246000fd5b8015614f81576ec097ce7bc90715b34b9f10000000000590565b806000808313156150c257670de0b6b3a76400009283811261509f57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d9082821461509357506706f05b59d3b20000905b8482136150675750505050500290565b808391020590671bc16d674ec80000821215615086575b831d90615057565b8091950194831d9061507e565b93505093925050020290565b6000199392508015614f81576ec097ce7bc90715b34b9f10000000000591614fd2565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60008112156151225768033dd1780914b97114198112613bcf57615119906000036150f3565b613b2d90614f97565b680a688906bd8affffff811361597657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615859575b66ff0000000000008316615751575b65ff00000000008316615651575b64ff000000008316615559575b63ff0000008316615469575b62ff00008316615381575b61ff0083166152a1575b60ff83166151ca575b02911c60bf031c90565b6080831661528f575b83831661527d575b6020831661526b575b60108316615259575b60088316615247575b60048316615235575b60028316615223575b60018316156151c0576801000000000000000102831c6151c0565b6801000000000000000102831c615208565b6801000000000000000302831c6151ff565b6801000000000000000602831c6151f6565b6801000000000000000b02831c6151ed565b6801000000000000001602831c6151e4565b6801000000000000002c02831c6151db565b6801000000000000005902831c6151d3565b618000831661536f575b614000831661535d575b612000831661534b575b6110008316615339575b6108008316615327575b6104008316615315575b6102008316615303575b6101008316156151b757680100000000000000b102831c6151b7565b6801000000000000016302831c6152e7565b680100000000000002c602831c6152dd565b6801000000000000058c02831c6152d3565b68010000000000000b1702831c6152c9565b6801000000000000162e02831c6152bf565b68010000000000002c5d02831c6152b5565b680100000000000058b902831c6152ab565b628000008316615457575b624000008316615445575b622000008316615433575b621000008316615421575b62080000831661540f575b6204000083166153fd575b6202000083166153eb575b620100008316156151ad576801000000000000b17202831c6151ad565b680100000000000162e402831c6153ce565b6801000000000002c5c802831c6153c3565b68010000000000058b9102831c6153b8565b680100000000000b172102831c6153ad565b68010000000000162e4302831c6153a2565b680100000000002c5c8602831c615397565b6801000000000058b90c02831c61538c565b63800000008316615547575b63400000008316615535575b63200000008316615523575b63100000008316615511575b630800000083166154ff575b630400000083166154ed575b630200000083166154db575b63010000008316156151a25768010000000000b1721802831c6151a2565b6801000000000162e43002831c6154bd565b68010000000002c5c86002831c6154b1565b680100000000058b90c002831c6154a5565b6801000000000b17217f02831c615499565b680100000000162e42ff02831c61548d565b6801000000002c5c85fe02831c615481565b68010000000058b90bfc02831c615475565b648000000000831661563f575b644000000000831661562d575b642000000000831661561b575b6410000000008316615609575b64080000000083166155f7575b64040000000083166155e5575b64020000000083166155d3575b64010000000083161561519657680100000000b17217f802831c615196565b68010000000162e42ff102831c6155b4565b680100000002c5c85fe302831c6155a7565b6801000000058b90bfce02831c61559a565b68010000000b17217fbb02831c61558d565b6801000000162e42fff002831c615580565b68010000002c5c8601cc02831c615573565b680100000058b90c0b4902831c615566565b65800000000000831661573f575b65400000000000831661572d575b65200000000000831661571b575b651000000000008316615709575b6508000000000083166156f7575b6504000000000083166156e5575b6502000000000083166156d3575b65010000000000831615615189576801000000b17218355102831c615189565b680100000162e430e5a202831c6156b3565b6801000002c5c863b73f02831c6156a5565b68010000058b90cf1e6e02831c615697565b680100000b1721bcfc9a02831c615689565b68010000162e43f4f83102831c61567b565b680100002c5c89d5ec6d02831c61566d565b6801000058b91b5bc9ae02831c61565f565b66800000000000008316615847575b66400000000000008316615835575b66200000000000008316615823575b66100000000000008316615811575b660800000000000083166157ff575b660400000000000083166157ed575b660200000000000083166157db575b660100000000000083161561517b5768010000b17255775c0402831c61517b565b6801000162e525ee054702831c6157ba565b68010002c5cc37da949202831c6157ab565b680100058ba01fb9f96d02831c61579c565b6801000b175effdc76ba02831c61578d565b680100162f3904051fa102831c61577e565b6801002c605e2e8cec5002831c61576f565b68010058c86da1c09ea202831c615760565b6780000000000000008316615957575b6740000000000000008316615945575b6720000000000000008316615933575b6710000000000000008316615921575b670800000000000000831661590f575b67040000000000000083166158fd575b67020000000000000083166158eb575b67010000000000000083161561516c57680100b1afa5abcbed6102831c61516c565b68010163da9fb33356d802831c6158c9565b680102c9a3e778060ee702831c6158b9565b6801059b0d31585743ae02831c6158a9565b68010b5586cf9890f62a02831c615899565b6801172b83c7d517adce02831c615889565b6801306fe0a31b7152df02831c615879565b5077b504f333f9de648480000000000000000000000000000000615869565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b90919060001983820983820291828083109203918083039214615a4557670de0b6b3a76400009081831015615a0e57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90615a955750805115615a6b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615ae0575b615aa6575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15615a9e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = @@ -40,73 +37,52 @@ contract Precompiles { DEPLOYERS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Deploys {SablierV2Comptroller} from precompiled bytecode. - function deployComptroller(address initialAdmin) public returns (ISablierV2Comptroller comptroller) { - bytes memory creationBytecode = bytes.concat(BYTECODE_COMPTROLLER, abi.encode(initialAdmin)); - assembly { - comptroller := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) - } - require( - address(comptroller) != address(0), "Sablier V2 Precompiles: deployment failed for Comptroller contract" - ); - } - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode, passing a default value for the /// `maxSegmentCount` parameter. /// @dev Notes: /// - A default value is passed for `maxSegmentCount`. /// - A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupDynamic( - address initialAdmin, - ISablierV2Comptroller initialComptroller - ) - public - returns (ISablierV2LockupDynamic lockupDynamic) - { + function deployLockupDynamic(address initialAdmin) public returns (ISablierV2LockupDynamic lockupDynamic) { uint256 maxSegmentCount = MAX_COUNT; - lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, maxSegmentCount); + lockupDynamic = deployLockupDynamic(initialAdmin, maxSegmentCount); } /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. function deployLockupDynamic( address initialAdmin, - ISablierV2Comptroller initialComptroller, uint256 maxSegmentCount ) public returns (ISablierV2LockupDynamic lockupDynamic) { ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, nftDescriptor, maxSegmentCount); + lockupDynamic = deployLockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); } /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. /// @dev A default value is passed for `maxSegmentCount`. function deployLockupDynamic( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor nftDescriptor ) public returns (ISablierV2LockupDynamic lockupDynamic) { - lockupDynamic = deployLockupDynamic(initialAdmin, initialComptroller, nftDescriptor, MAX_COUNT); + lockupDynamic = deployLockupDynamic(initialAdmin, nftDescriptor, MAX_COUNT); } /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. function deployLockupDynamic( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor nftDescriptor, uint256 maxSegmentCount ) public returns (ISablierV2LockupDynamic lockupDynamic) { - bytes memory creationBytecode = bytes.concat( - BYTECODE_LOCKUP_DYNAMIC, abi.encode(initialAdmin, initialComptroller, nftDescriptor, maxSegmentCount) - ); + bytes memory creationBytecode = + bytes.concat(BYTECODE_LOCKUP_DYNAMIC, abi.encode(initialAdmin, nftDescriptor, maxSegmentCount)); assembly { lockupDynamic := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } @@ -117,28 +93,20 @@ contract Precompiles { /// @notice Deploys {SablierV2LockupLinear} from precompiled bytecode. /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupLinear( - address initialAdmin, - ISablierV2Comptroller initialComptroller - ) - public - returns (ISablierV2LockupLinear lockupLinear) - { + function deployLockupLinear(address initialAdmin) public returns (ISablierV2LockupLinear lockupLinear) { ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); - lockupLinear = deployLockupLinear(initialAdmin, initialComptroller, nftDescriptor); + lockupLinear = deployLockupLinear(initialAdmin, nftDescriptor); } /// @notice Deploys {SablierV2LockupLinear} from precompiled bytecode. function deployLockupLinear( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor nftDescriptor ) public returns (ISablierV2LockupLinear lockupLinear) { - bytes memory creationBytecode = - bytes.concat(BYTECODE_LOCKUP_LINEAR, abi.encode(initialAdmin, initialComptroller, nftDescriptor)); + bytes memory creationBytecode = bytes.concat(BYTECODE_LOCKUP_LINEAR, abi.encode(initialAdmin, nftDescriptor)); assembly { lockupLinear := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } @@ -152,57 +120,47 @@ contract Precompiles { /// @dev Notes: /// - A default value is passed for `maxTrancheCount`. /// - A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupTranched( - address initialAdmin, - ISablierV2Comptroller initialComptroller - ) - public - returns (ISablierV2LockupTranched lockupTranched) - { + function deployLockupTranched(address initialAdmin) public returns (ISablierV2LockupTranched lockupTranched) { uint256 maxTrancheCount = MAX_COUNT; - lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, maxTrancheCount); + lockupTranched = deployLockupTranched(initialAdmin, maxTrancheCount); } /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. function deployLockupTranched( address initialAdmin, - ISablierV2Comptroller initialComptroller, uint256 maxTrancheCount ) public returns (ISablierV2LockupTranched lockupTranched) { ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); - lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, nftDescriptor, maxTrancheCount); + lockupTranched = deployLockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); } /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. /// @dev A default value is passed for `maxTrancheCount`. function deployLockupTranched( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor nftDescriptor ) public returns (ISablierV2LockupTranched lockupTranched) { - lockupTranched = deployLockupTranched(initialAdmin, initialComptroller, nftDescriptor, MAX_COUNT); + lockupTranched = deployLockupTranched(initialAdmin, nftDescriptor, MAX_COUNT); } /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. function deployLockupTranched( address initialAdmin, - ISablierV2Comptroller initialComptroller, ISablierV2NFTDescriptor nftDescriptor, uint256 maxTrancheCount ) public returns (ISablierV2LockupTranched lockupTranched) { - bytes memory creationBytecode = bytes.concat( - BYTECODE_LOCKUP_TRANCHED, abi.encode(initialAdmin, initialComptroller, nftDescriptor, maxTrancheCount) - ); + bytes memory creationBytecode = + bytes.concat(BYTECODE_LOCKUP_TRANCHED, abi.encode(initialAdmin, nftDescriptor, maxTrancheCount)); assembly { lockupTranched := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } @@ -225,24 +183,22 @@ contract Precompiles { /// @notice Deploys all V2 Core contracts in the following order: /// - /// 1. {SablierV2Comptroller} - /// 2. {SablierV2NFTDescriptor} - /// 3. {SablierV2LockupDynamic} - /// 4. {SablierV2LockupLinear} + /// 1. {SablierV2NFTDescriptor} + /// 2. {SablierV2LockupDynamic} + /// 3. {SablierV2LockupLinear} + /// 4. {SablierV2LockupTranched} function deployCore(address initialAdmin) public returns ( - ISablierV2Comptroller comptroller, ISablierV2LockupDynamic lockupDynamic, ISablierV2LockupLinear lockupLinear, ISablierV2LockupTranched lockupTranched, ISablierV2NFTDescriptor nftDescriptor ) { - comptroller = deployComptroller(initialAdmin); nftDescriptor = deployNFTDescriptor(); - lockupDynamic = deployLockupDynamic(initialAdmin, comptroller); - lockupLinear = deployLockupLinear(initialAdmin, comptroller); - lockupTranched = deployLockupTranched(initialAdmin, comptroller); + lockupDynamic = deployLockupDynamic(initialAdmin); + lockupLinear = deployLockupLinear(initialAdmin); + lockupTranched = deployLockupTranched(initialAdmin); } } diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 164deba46..6fdbac31d 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { ISablierV2Comptroller } from "../../src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; @@ -24,37 +23,27 @@ contract Precompiles_Test is Base_Test { } } - function test_DeployComptroller() external onlyTestOptimizedProfile { - address actualComptroller = address(precompiles.deployComptroller(users.admin)); - address expectedComptroller = address(deployOptimizedComptroller(users.admin)); - assertEq(actualComptroller.code, expectedComptroller.code, "bytecodes mismatch"); - } - function test_DeployLockupDynamic() external onlyTestOptimizedProfile { - ISablierV2Comptroller comptroller = precompiles.deployComptroller(users.admin); - address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, comptroller, nftDescriptor)); + address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, nftDescriptor)); address expectedLockupDynamic = - address(deployOptimizedLockupDynamic(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT())); + address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, defaults.MAX_COUNT())); bytes memory expectedLockupDynamicCode = adjustBytecode(expectedLockupDynamic.code, expectedLockupDynamic, actualLockupDynamic); assertEq(actualLockupDynamic.code, expectedLockupDynamicCode, "bytecodes mismatch"); } function test_DeployLockupLinear() external onlyTestOptimizedProfile { - ISablierV2Comptroller comptroller = precompiles.deployComptroller(users.admin); - address actualLockupLinear = address(precompiles.deployLockupLinear(users.admin, comptroller, nftDescriptor)); - address expectedLockupLinear = address(deployOptimizedLockupLinear(users.admin, comptroller, nftDescriptor)); + address actualLockupLinear = address(precompiles.deployLockupLinear(users.admin, nftDescriptor)); + address expectedLockupLinear = address(deployOptimizedLockupLinear(users.admin, nftDescriptor)); bytes memory expectedLockupLinearCode = adjustBytecode(expectedLockupLinear.code, expectedLockupLinear, actualLockupLinear); assertEq(actualLockupLinear.code, expectedLockupLinearCode, "bytecodes mismatch"); } function test_DeployLockupTranched() external onlyTestOptimizedProfile { - ISablierV2Comptroller comptroller = precompiles.deployComptroller(users.admin); - address actualLockupTranched = - address(precompiles.deployLockupTranched(users.admin, comptroller, nftDescriptor)); + address actualLockupTranched = address(precompiles.deployLockupTranched(users.admin, nftDescriptor)); address expectedLockupTranched = - address(deployOptimizedLockupTranched(users.admin, comptroller, nftDescriptor, defaults.MAX_COUNT())); + address(deployOptimizedLockupTranched(users.admin, nftDescriptor, defaults.MAX_COUNT())); bytes memory expectedLockupTranchedCode = adjustBytecode(expectedLockupTranched.code, expectedLockupTranched, actualLockupTranched); assertEq(actualLockupTranched.code, expectedLockupTranchedCode, "bytecodes mismatch"); @@ -68,7 +57,6 @@ contract Precompiles_Test is Base_Test { function test_DeployCore() external onlyTestOptimizedProfile { ( - ISablierV2Comptroller actualComptroller, ISablierV2LockupDynamic actualLockupDynamic, ISablierV2LockupLinear actualLockupLinear, ISablierV2LockupTranched actualLockupTranched, @@ -76,12 +64,11 @@ contract Precompiles_Test is Base_Test { ) = precompiles.deployCore(users.admin); ( - ISablierV2Comptroller expectedComptroller, ISablierV2LockupDynamic expectedLockupDynamic, ISablierV2LockupLinear expectedLockupLinear, ISablierV2LockupTranched expectedLockupTranched, ISablierV2NFTDescriptor expectedNFTDescriptor - ) = deployOptimizedCore(users.admin, defaults.MAX_COUNT(), defaults.MAX_COUNT()); + ) = deployOptimizedCore(users.admin, defaults.MAX_COUNT()); bytes memory expectedLockupDynamicCode = adjustBytecode( address(expectedLockupDynamic).code, address(expectedLockupDynamic), address(actualLockupDynamic) @@ -95,7 +82,6 @@ contract Precompiles_Test is Base_Test { address(expectedLockupTranched).code, address(expectedLockupTranched), address(actualLockupTranched) ); - assertEq(address(actualComptroller).code, address(expectedComptroller).code, "bytecodes mismatch"); assertEq(address(actualLockupDynamic).code, expectedLockupDynamicCode, "bytecodes mismatch"); assertEq(address(actualLockupLinear).code, expectedLockupLinearCode, "bytecodes mismatch"); assertEq(address(actualLockupTranched).code, expectedLockupTranchedCode, "bytecodes mismatch"); From 34c7bf632aae985aed8413b04db8576d10603256 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 11 Mar 2024 17:00:47 +0200 Subject: [PATCH 057/132] test: update precompiles bytecode --- test/utils/Precompiles.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index 76c26e591..9997d9932 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -25,11 +25,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0346200046e57601f62005f8a38819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601d82527f5361626c696572205632204c6f636b75702044796e616d6963204e46540000006020830152620000be62000473565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051615af6908162000494823960805181613d2b015260a051818181610e350152613e4c0152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a714612a185750806306fdde031461291b578063081812fc146128fd578063095ea7b3146127f65780631400ecec146127505780631c1cdd4c146126ea5780631e99d569146126cc57806323b872dd146126b557806331df3d48146125b257806339a73c031461256f57806340e58ee514612277578063425d30dd1461222157806342842e0e146121d057806342966c6814611fbd5780634426757014611f965780634857501f14611f1c5780634869e12d14611edf5780634cc55e1114611de457806354c0229214611b485780635fe3b56714611b215780636352211e14611af25780636d0cee7514611af257806370a0823114611a7e57806375829def146119e45780637cad6cd1146118e65780637de6b1db146116c95780638659c27014611379578063894e9a0d14610ff35780638bad38dd14610f485780638f69b99314610ead5780639067b67714610e585780639188ec8414610e1d57806395d89b4114610d09578063a22cb46514610c4b578063a6202bf214610b43578063a80fc07114610aec578063ad35efd414610a73578063b256456914610a1d578063b637b865146109be578063b88d4fde14610935578063b8a3be66146108ff578063b971302a146108ab578063bc063e1a14610888578063bc2be1be14610833578063c156a11d146106dd578063c87b56dd146105c9578063cc364f481461052d578063d4dbd20b146104d6578063d511609f14610485578063d975dfed14610437578063e985e9c5146103e0578063ea5ead19146103b2578063eac8f5b81461035b578063f590c176146102f6578063f851a440146102cf5763fdd46d601461028957600080fd5b346102ca5760603660031901126102ca576102a2612b44565b604435906001600160801b03821682036102ca576102c8926102c2613d21565b3561371c565b005b600080fd5b346102ca5760003660031901126102ca5760206001600160a01b0360005416604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360016040600020015416604051908152f35b50346102ca5760403660031901126102ca576102c890356103d1612b44565b6103da8261467a565b9161337a565b346102ca5760403660031901126102ca576103f9612b2e565b610401612b44565b906001600160a01b03809116600052600860205260406000209116600052602052602060ff604060002054166040519015158152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760206104748361467a565b6001600160801b0360405191168152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060026040600020015460801c604051908152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360036040600020015416604051908152f35b50346102ca5760203660031901126102ca578035906000602060405161055281612c94565b828152015281600052600b60205260ff60016040600020015460a81c16156103465750600052600b6020526040806000205464ffffffffff82519161059683612c94565b818160a01c16835260c81c1660208201526105c7825180926020908164ffffffffff91828151168552015116910152565bf35b50346102ca576020806003193601126102ca57600082356105e981613aa2565b5060446001600160a01b03600a54169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106d157600092610658575b50610654604051928284938452830190612b09565b0390f35b9091503d806000833e61066b8183612ce1565b81019082818303126102ca5780519067ffffffffffffffff82116102ca570181601f820112156102ca5780516106a081612d03565b926106ae6040519485612ce1565b8184528482840101116102ca576106ca91848085019101612ae6565b903861063f565b6040513d6000823e3d90fd5b50346102ca5760403660031901126102ca578035906106fa612b44565b91610703613d21565b80600052600b60205260ff60016040600020015460a81c161561081d578060005260056020526001600160a01b038060406000205416938433036107fa5761074a8361467a565b6001600160801b0381166107e9575b50818116156107d1578261076c91613bdc565b9081168061078b576024848460405191637e27328960e01b8352820152fd5b840361079357005b6107cd916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107f490868561337a565b38610759565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460a01c16604051908152f35b346102ca5760003660031901126102ca57602060405167016345785d8a00008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160a01b0360406000205416604051908152f35b50346102ca5760203660031901126102ca5735600052600b602052602060ff60016040600020015460a81c166040519015158152f35b50346102ca5760803660031901126102ca5761094f612b2e565b610957612b44565b906064359267ffffffffffffffff84116102ca57366023850112156102ca578301359161098383612d03565b926109916040519485612ce1565b80845236602482870101116102ca5760208160009260246102c89801838801378501015260443591613206565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600c602052610654610a096040600020613176565b604051918291602083526020830190612bd4565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460b01c166040519015158152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610aad90613b55565b604051906005811015610ac257602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b60205260206001600160801b0360026040600020015416604051908152f35b50346102ca5760203660031901126102ca57610b5d612b2e565b906001600160a01b038060005416338103610c1c57508216918260005260026020526001600160801b0360406000205416918215610bec575081610bbe9184600052600260205260406000206001600160801b0319815416905533906145ee565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a3005b60249084604051917f8410168c000000000000000000000000000000000000000000000000000000008352820152fd5b604080516331b339a960e21b81526001600160a01b039092169382019384523360208501529092839250010390fd5b50346102ca5760403660031901126102ca57610c65612b2e565b602435908115158092036102ca576001600160a01b0316918215610cd95750336000526008602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760003660031901126102ca576040519060009080549160018360011c9260018516948515610e13575b6020958686108114610dfe57858852879493929187908215610ddc575050600114610d80575b5050610d6c92500383612ce1565b610654604051928284938452830190612b09565b8592506000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b906000915b858310610dc4575050610d6c93508201013880610d5e565b80548389018501528794508693909201918101610dac565b9250935050610d6c94915060ff191682840152151560051b8201013880610d5e565b602283634e487b7160e01b6000525260246000fd5b93607f1693610d38565b346102ca5760003660031901126102ca5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602064ffffffffff60406000205460c81c16604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad757610ee790613b55565b9060058210159081610f255760028314918215610f3a575b8215610f13575b6020836040519015158152f35b909150610f2557602091143880610f06565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610eff565b50346102ca5760203660031901126102ca5780356001600160a01b03918282168092036102ca578260005416338103610fc557505060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a2005b604080516331b339a960e21b81526001600160a01b0390921692820192835233602084015290918291010390fd5b50346102ca5760203660031901126102ca57604051610160810181811067ffffffffffffffff821117611364576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e0820152600061010082015261106e613123565b61012082015201528035600052600b60205260ff60016040600020015460a81c161561134c578035600052600b60205260406000209061113e6002604051936110b685612cc4565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613142565b61012083015261114e8135613b55565b60058110156113375760021461132b575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600c602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761131657506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161123990613176565b82820152610654604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261130261012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190612bd4565b604190634e487b7160e01b6000525260246000fd5b6000606083015261115f565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b50346102ca57602090816003193601126102ca57803567ffffffffffffffff81116102ca576113ab9036908301612ba3565b90926113b5613d21565b6000915b8083106113c257005b6113cd8382876130c8565b35926113d7613d21565b83600052600b9081845260ff9160019280846040600020015460a81c16156116b357866000528186526040600020818582015460a01c1660001461142c576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c61169c5761145c81600052600b6020526001600160a01b0360406000205416331490565b1561167a5761146a81613add565b92816000528088526114826002604060002001613142565b936001600160801b03938486511685831610156116635783600052828a5260406000205460f01c161561164c5780848a6114c26114cc94838a5116612d57565b9701511690612d57565b9382600052818952886040600020977f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50895497600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a16178b5560038882169b8c15611633575b0197851697886001600160801b03198254161790556001600160a01b038099169889936005865281604060002054169788965260406000200154169461157c8985886145ee565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6115df575b50505050600191500191906113b9565b803b156102ca578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611624575b8080806115cf565b61162d90612cb0565b3861161c565b848101600160a01b60ff60a01b19825416179055611535565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b50346102ca57602090816003193601126102ca5780356116e7613d21565b80600052600b835260ff60016040600020015460a81c161561081d5761170c81613b55565b926005841015610ac257838303611734576024838360405191634a5541ef60e01b8352820152fd5b6003840361175357602483836040519163fe19f19f60e01b8352820152fd5b90600284146118cf5761177c81600052600b6020526001600160a01b0360406000205416331490565b156118ad5780600052600b825260ff60406000205460f01c16156118965780600052600b8252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600583526001600160a01b036040600020541693843b611822575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b156102ca578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611887575b806117f6565b61189090612cb0565b83611881565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b50346102ca5760203660031901126102ca5780356001600160a01b03908181168091036102ca5781600054163381036119b85750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26009546000198101919082116119a3577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576119fe612b2e565b600054906001600160a01b0390818316338103611a5257506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b50346102ca5760203660031901126102ca576001600160a01b03611aa0612b2e565b16908115611ac1575060005260066020526020604060002054604051908152f35b6024906000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b50346102ca5760203660031901126102ca57611b1060209135613aa2565b6001600160a01b0360405191168152f35b346102ca5760003660031901126102ca5760206001600160a01b0360015416604051908152f35b50346102ca576020906003199082823601126102ca5780359167ffffffffffffffff908184116102ca57610120843603918201126102ca57611b88613d21565b60c484013590602219018112156102ca57830182810135908282116102ca5760240160608202360381136102ca57611bc1913691612ff9565b9283519281611bcf85612fe1565b94611bdd6040519687612ce1565b808652601f19611bec82612fe1565b018860005b828110611dc65750505064ffffffffff90814216956001600160801b039889611c1982613d7d565b515116828c611c2784613d7d565b5101511685806040611c3886613d7d565b510151168b01169060405192611c4d84612c78565b83528d8301526040820152611c618a613d7d565b52611c6b89613d7d565b5060019360015b8c8b8d878410611d3757908c8a611c8a818e01613102565b92611c9760248301613102565b92611ca4604484016130ee565b946064840135946001600160a01b03958681168091036102ca57611d2f98611cef98611d2498611cd660848a01613116565b9481611ce460a48c01613116565b976040519d8e612c45565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613099565b610100820152613d9e565b604051908152f35b8899509084806040611d748a87611d648c9d9e9f9b9c99988b90611d5b828d613d8a565b5151169a613d8a565b5101511694600019890190613d8a565b51015116816040611d85888c613d8a565b5101511601169160405193611d9985612c78565b84528301526040820152611dad828d613d8a565b52611db8818c613d8a565b500190879594939291611c72565b9091929350611dd3613123565b82828a010152019088859392611bf1565b50346102ca5760403660031901126102ca5767ffffffffffffffff9080358281116102ca57611e169036908301612ba3565b926024359081116102ca57611e2e9036908401612ba3565b919092611e39613d21565b828503611ea9575060005b848110611e4d57005b80611ea3611e5e60019388866130c8565b35611e6a8389876130c8565b3560005260056020526001600160a01b0360406000205416611e95611e9085898b6130c8565b6130ee565b91611e9e613d21565b61371c565b01611e44565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657602061047483614b1c565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c161561034657600090611f5a83613b55565b906005821015610f255750600203611f7a575b6020906040519015158152f35b50600052600b602052602060ff60406000205460f01c16611f6d565b346102ca5760003660031901126102ca5760206001600160a01b03600a5416604051908152f35b50346102ca57602090816003193601126102ca57803591611fdc613d21565b82600052600b815260ff60016040600020015460a81c16156121ba5782600052600b815260ff60016040600020015460a01c161561218a5761201d83614585565b156121665782600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c1615908161215c575b5080612154575b61213d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526005835260406000205416918215928315612102575b856000526005825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a16120ec57005b60249160405191637e27328960e01b8352820152fd5b61212386600052600760205260406000206001600160a01b03198154169055565b80600052600682526040600020600019815401905561209c565b6024838560405191630da9b01360e01b8352820152fd5b50600061205c565b9050151538612055565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b50346102ca576121df36612b6e565b90604051926020840184811067ffffffffffffffff82111761220c576102c8955060405260008452613206565b604186634e487b7160e01b6000525260246000fd5b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465750600052600b602052602060ff60016040600020015460a01c166040519015158152f35b50346102ca57602090816003193601126102ca578035612295613d21565b80600052600b80845260ff60016040600020015460a81c16156125595781600052808452604060002060ff600182015460a01c166000146122e7576024848460405191634a5541ef60e01b8352820152fd5b5460f81c6125425761230f82600052600b6020526001600160a01b0360406000205416331490565b156125205761231d82613add565b92826000528185526123356002604060002001613142565b936001600160801b0390818651168282161015612509578460005283875260ff60406000205460f01c16156124f257866123c482847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a6123ba7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612d57565b9a01511690612d57565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156124d8575b0195811695866001600160801b03198254161790556001600160a01b03809a169a8b91600586528a6124828d604060002054169d8e96895260016040600020015416966124588b878a6145ee565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61249457005b843b156102ca576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16124cf57005b6102c890612cb0565b60018101600160a01b60ff60a01b1982541617905561240a565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b346102ca5760203660031901126102ca576001600160a01b03612590612b2e565b16600052600260205260206001600160801b0360406000205416604051908152f35b50346102ca57600319906020368301126102ca5780359167ffffffffffffffff908184116102ca576101409084360301126102ca576125ef613d21565b604051906125fc82612c45565b612607848401612b5a565b825261261560248501612b5a565b602083015261262660448501612d1f565b604083015261263760648501612b5a565b606083015261264860848501612c38565b608083015261265960a48501612c38565b60a083015261266a60c48501612fcf565b60c083015260e48401359081116102ca57830191366023840112156102ca576020936126a5611d2492611d2f95602436928201359101612ff9565b60e0840152610104369101613099565b346102ca576102c86126c636612b6e565b91612d86565b346102ca5760003660031901126102ca576020600954604051908152f35b50346102ca5760203660031901126102ca57803580600052600b60205260ff60016040600020015460a81c1615610ad75761272490613b55565b906005821015610f255760208215838115612745575b506040519015158152f35b60019150148261273a565b50346102ca5760203660031901126102ca5780359081600052600b60205260ff60016040600020015460a81c16156103465760208260009080600052600b8352604060002060ff815460f01c16806127e4575b6127bb575b50506001600160801b0360405191168152f35b6127dd92506001600160801b0360026127d79201541691613add565b90612d57565b82806127a8565b5060ff600182015460a01c16156127a3565b50346102ca5760403660031901126102ca57612810612b2e565b906024359061281e82613aa2565b90331515806128ea575b806128bc575b61288b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260076020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600860205260406000203360005260205260ff604060002054161561282e565b50336001600160a01b0383161415612828565b50346102ca5760203660031901126102ca57611b1060209135612d33565b50346102ca5760003660031901126102ca576040519060006003549060018260011c92600181168015612a0e575b60209586861082146129f9575084875286939291869082156129d957505060011461297c575b50610d6c92500383612ce1565b84915060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000915b8583106129c1575050610d6c93508201013861296f565b805483890185015287945086939092019181016129aa565b60ff191685820152610d6c95151560051b850101925038915061296f9050565b602290634e487b7160e01b6000525260246000fd5b93607f1693612949565b82346102ca5760203660031901126102ca5735907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102ca57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612abc575b8115612a92575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612a8b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612a84565b60005b838110612af95750506000910152565b8181015183820152602001612ae9565b90602091612b2281518092818552858086019101612ae6565b601f01601f1916010190565b600435906001600160a01b03821682036102ca57565b602435906001600160a01b03821682036102ca57565b35906001600160a01b03821682036102ca57565b60609060031901126102ca576001600160a01b039060043582811681036102ca579160243590811681036102ca579060443590565b9181601f840112156102ca5782359167ffffffffffffffff83116102ca576020808501948460051b0101116102ca57565b90815180825260208080930193019160005b828110612bf4575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612be6565b359081151582036102ca57565b610120810190811067ffffffffffffffff821117612c6257604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612c6257604052565b6040810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257604052565b610140810190811067ffffffffffffffff821117612c6257604052565b90601f8019910116810190811067ffffffffffffffff821117612c6257604052565b67ffffffffffffffff8111612c6257601f01601f191660200190565b35906001600160801b03821682036102ca57565b612d3c81613aa2565b5060005260076020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612d7057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612fb75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c16159081612fad575b5080612fa5575b612f8e578685526005815282848620541694873315159384612ede575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612ea6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612e785750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612ec782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055612e14565b91929380915090612f4d575b15612ef85790878392612deb565b848887612f15576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612f72575b80612eea5750878252600783523384868420541614612eea565b5085825260088352848220338352835260ff8583205416612f58565b602487855190630da9b01360e01b82526004820152fd5b506001612dce565b9050151538612dc7565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff821682036102ca57565b67ffffffffffffffff8111612c625760051b60200190565b92919261300582612fe1565b6040946130156040519283612ce1565b819584835260208093019160608096028501948186116102ca57925b8584106130415750505050505050565b86848303126102ca5782519061305682612c78565b61305f85612d1f565b8252858501359067ffffffffffffffff821682036102ca57828792838b95015261308a868801612fcf565b86820152815201930192613031565b91908260409103126102ca576040516130b181612c94565b60208082946130bf81612b5a565b84520135910152565b91908110156130d85760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036102ca5790565b356001600160a01b03811681036102ca5790565b3580151581036102ca5790565b6040519061313082612c78565b60006040838281528260208201520152565b9060405161314f81612c78565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b90815461318281612fe1565b926040936131936040519182612ce1565b82815280946020809201926000526020600020906000935b8585106131ba57505050505050565b600184819284516131ca81612c78565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c16868201528152019301940193916131ab565b9190613213828285612d86565b803b613220575b50505050565b61327c6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612b09565b03906020816000938185885af190829082613312575b50506132c957826132a161464a565b80519190826132c25760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036132fa57503880808061321a565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613372575b8161332f60209383612ce1565b8101031261336e5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361336b5750903880613292565b80fd5b5080fd5b3d9150613322565b92919092613386613d21565b600093818552600b9260209380855260409260ff6001858a20015460a81c16156137065784885281865260ff6001858a20015460a01c166136ef576001600160a01b03918282169283156136df576001600160801b03938486169182156136c857888c5260058a5280888d2054169384831415806136b8575b6136955761340c8a61467a565b878116851161366457508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061343d916146a2565b878752838652828720600201908282549160801b6001600160801b031916911617815561346990613142565b90808683015116918184818351169201511661348491612d57565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d96613637575b878252855220015416946134c78189886145ee565b8a51908152a4803314158061362d575b6135c8575b8233141590816135bd575b816135b2575b50613521575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156135ae578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af161359f575b8594816134f3565b6135a890612cb0565b38613597565b8780fd5b9050821415386134ed565b833b151591506134e7565b803b15613629578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af161361a575b506134dc565b61362390612cb0565b38613614565b8880fd5b50803b15156134d7565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134b2565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506136c28a614585565b156133ff565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b92919092600093818552600b9060209382855260409260ff6001858a20015460a81c1615613706578785815281875260ff6001868320015460a01c16613a8b576001600160a01b0390818516928315613a7b576001600160801b0393848616918215613a645789845260058b52848985205416948583141580613a54575b613a31576137c18b838e6137ad83614b1c565b9289525260028c8820015460801c90612d57565b8781168511613a005750908b8b928387528282528b808820998b838c54169b6002015460801c906137f1916146a2565b868a52858552828a20600201908282549160801b6001600160801b031916911617815561381d90613142565b8180868301511693818351169201511661383691612d57565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936139d2575b848852825260018c88200154169461387a818c886145ee565b8b51908152a481331415806139c8575b613962575b50813314159081613957575b8161394c575b506138d4575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613948578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613930575b80806134f3565b61393a8691612cb0565b6139445784613929565b8480fd5b8280fd5b9050811415386138a1565b823b1515915061389b565b813b1561336b578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16139b4575b5061388f565b6139c091929a50612cb0565b9738806139ae565b50813b151561388a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613861565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b50613a5e8b614585565b1561379a565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260056020526001600160a01b0360406000205416908115613ac5575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff80421682600052600b602052604060002091825482828260a01c161015613b4b5760c81c161115613b395750600c602052600160406000205411600014613b3057613b2d9061478e565b90565b613b2d906146bd565b6001600160801b039150600201541690565b5050505050600090565b80600052600b602052604060002060ff600182015460a01c16600014613b7c575050600490565b805460f81c613bd5575460a01c64ffffffffff164210613bcf57613b9f81613add565b90600052600b6020526001600160801b038060026040600020015416911610600014613bca57600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613d17575b5080613d0c575b613cf5579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613cbd575b169283613ca7575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613c83565b613cde86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613c7b565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c1a565b9050151538613c13565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613d5357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b8051156130d85760200190565b80518210156130d85760209160051b010190565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156106d157600090614551575b613e2091506001600160801b0360408501511690602061010086015101519161496e565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452757815180156144fd577f000000000000000000000000000000000000000000000000000000000000000081116144cc575064ffffffffff6040613e8384613d7d565b510151168110156144755750600090819082815184905b8082106143e4575050505064ffffffffff421664ffffffffff82168110156143a45750506001600160801b031680820361436d5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000604061402d8951996000198b0190613d8a565b51015160c81b169560f01b16911617171717845560005b81811061429b575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b036020830151168015612fb7576140cf866001600160a01b0392613bdc565b1661426a576141046001600160a01b036060840151166001600160801b03808451168160208601511601169030903390614aad565b6001600160801b036040820151168061423a575b507fef3d668acee46576ad5d407c42ab4d0cde13f3cd70b28f09a0fb9e3bf5bf09cb6141f76001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661422f61420f60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a38c612c94565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190612bd4565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b614264906001600160a01b036060850151166001600160a01b036101008601515116903390614aad565b38614118565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906142b88160e0870151613d8a565b51825468010000000000000000811015612c6257600181018085558110156130d857600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501614044565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614408906001600160801b036143ff8588613d8a565b515116906146a2565b9364ffffffffff80604061441c8685613d8a565b5101511694168085111561443857506001849301909291613e9a565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061448684613d7d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161457d575b8161456b60209383612ce1565b810103126102ca57613e209051613dfc565b3d915061455e565b60009080825260056020526001600160a01b0380604084205416928333149384156145ca575b505082156145b857505090565b9091506145c53392612d33565b161490565b60ff92945090604091815260086020528181203382526020522054169138806145ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261464891614643606483612ce1565b614b97565b565b3d15614675573d9061465b82612d03565b916146696040519384612ce1565b82523d6000602084013e565b606090565b613b2d9061468781614b1c565b90600052600b60205260026040600020015460801c90612d57565b9190916001600160801b0380809416911601918211612d7057565b64ffffffffff6146f2600091838352600b60205280806040852054818160a01c1693849160c81c160316918142160316614c33565b91808252600c6020526040822080541561477a5790829167ffffffffffffffff935261474c6020832054828452600b6020526147476001600160801b03968760026040882001541696879360801c1690614d23565b614d91565b92831361476257505061475e90614e7b565b1690565b60029350604092508152600b60205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff8042166000838152600b602052604091828220908351916147b483612cc4565b80549661012061483a60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201613142565b94019384528452600c602052614851858520613176565b918496808761485f86613d7d565b5101511692828288955b16106149385750916148ed614747928488816148f298976001600160801b039e8f614894898c613d8a565b5151169d8e9a67ffffffffffffffff60206148af8c84613d8a565b510151169984836148c08385613d8a565b510151169650801561492c576148dc9293506000190190613d8a565b5101511680925b0316920316614c33565b614d23565b92831361490b5750506149058391614e7b565b16011690565b5160200151929392831692841683101591506149279050575090565b905090565b505050511680926148e3565b8093986001600160801b03908161494f8c89613d8a565b51511601169801928282808a614965888a613d8a565b51015116614869565b909291614979613123565b936001600160801b0392838116918215614a855767016345785d8a0000808211614a4e57808511614a1757506149c3856149b48193866159a7565b169460208901958652846159a7565b1691846149da6040890194808652828751166146a2565b161015614a01576149f38491826149fc95511690612d57565b91511690612d57565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614a9881612c78565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612c625761464892604052614b97565b80600052600b602052614b356002604060002001613142565b81600052600b602052604060002060ff600182015460a01c16600014614b6857506001600160801b039150602001511690565b5460f81c614b7a5750613b2d90613add565b613b2d91506001600160801b036040818351169201511690612d57565b6001600160a01b031690614bc2600080836020829551910182875af1614bbb61464a565b9084615a56565b908151918215159283614c0b575b505050614bda5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261336e57602001519081159182150361336b5750388080614bd0565b600160ff1b808214908115614d19575b50614cef576000811215614ce657614c6c816000035b6000841215614cdf578360000390614eb7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614ca85760001991181315614ca25790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614eb7565b614c6c81614c59565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b9050821438614c43565b80614d3e5750614d3957670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614d8b575080614d63575050670de0b6b3a764000090565b670de0b6b3a76400008114614d8757614d8290614747613b2d93614fb1565b6150f3565b5090565b91505090565b600160ff1b808214908115614e71575b50614e47576000811215614e3e57614dca816000035b6000841215614e375783600003906159a7565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614e005760001991181315614ca25790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906159a7565b614dca81614db7565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614da1565b60008112614e865790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b670de0b6b3a7640000916000198383099280830292838086109503948086039514614f735782851015614f3757908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614f81570490565b634e487b7160e01b600052601260045260246000fd5b8015614f81576ec097ce7bc90715b34b9f10000000000590565b806000808313156150c257670de0b6b3a76400009283811261509f57506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d9082821461509357506706f05b59d3b20000905b8482136150675750505050500290565b808391020590671bc16d674ec80000821215615086575b831d90615057565b8091950194831d9061507e565b93505093925050020290565b6000199392508015614f81576ec097ce7bc90715b34b9f10000000000591614fd2565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60008112156151225768033dd1780914b97114198112613bcf57615119906000036150f3565b613b2d90614f97565b680a688906bd8affffff811361597657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615859575b66ff0000000000008316615751575b65ff00000000008316615651575b64ff000000008316615559575b63ff0000008316615469575b62ff00008316615381575b61ff0083166152a1575b60ff83166151ca575b02911c60bf031c90565b6080831661528f575b83831661527d575b6020831661526b575b60108316615259575b60088316615247575b60048316615235575b60028316615223575b60018316156151c0576801000000000000000102831c6151c0565b6801000000000000000102831c615208565b6801000000000000000302831c6151ff565b6801000000000000000602831c6151f6565b6801000000000000000b02831c6151ed565b6801000000000000001602831c6151e4565b6801000000000000002c02831c6151db565b6801000000000000005902831c6151d3565b618000831661536f575b614000831661535d575b612000831661534b575b6110008316615339575b6108008316615327575b6104008316615315575b6102008316615303575b6101008316156151b757680100000000000000b102831c6151b7565b6801000000000000016302831c6152e7565b680100000000000002c602831c6152dd565b6801000000000000058c02831c6152d3565b68010000000000000b1702831c6152c9565b6801000000000000162e02831c6152bf565b68010000000000002c5d02831c6152b5565b680100000000000058b902831c6152ab565b628000008316615457575b624000008316615445575b622000008316615433575b621000008316615421575b62080000831661540f575b6204000083166153fd575b6202000083166153eb575b620100008316156151ad576801000000000000b17202831c6151ad565b680100000000000162e402831c6153ce565b6801000000000002c5c802831c6153c3565b68010000000000058b9102831c6153b8565b680100000000000b172102831c6153ad565b68010000000000162e4302831c6153a2565b680100000000002c5c8602831c615397565b6801000000000058b90c02831c61538c565b63800000008316615547575b63400000008316615535575b63200000008316615523575b63100000008316615511575b630800000083166154ff575b630400000083166154ed575b630200000083166154db575b63010000008316156151a25768010000000000b1721802831c6151a2565b6801000000000162e43002831c6154bd565b68010000000002c5c86002831c6154b1565b680100000000058b90c002831c6154a5565b6801000000000b17217f02831c615499565b680100000000162e42ff02831c61548d565b6801000000002c5c85fe02831c615481565b68010000000058b90bfc02831c615475565b648000000000831661563f575b644000000000831661562d575b642000000000831661561b575b6410000000008316615609575b64080000000083166155f7575b64040000000083166155e5575b64020000000083166155d3575b64010000000083161561519657680100000000b17217f802831c615196565b68010000000162e42ff102831c6155b4565b680100000002c5c85fe302831c6155a7565b6801000000058b90bfce02831c61559a565b68010000000b17217fbb02831c61558d565b6801000000162e42fff002831c615580565b68010000002c5c8601cc02831c615573565b680100000058b90c0b4902831c615566565b65800000000000831661573f575b65400000000000831661572d575b65200000000000831661571b575b651000000000008316615709575b6508000000000083166156f7575b6504000000000083166156e5575b6502000000000083166156d3575b65010000000000831615615189576801000000b17218355102831c615189565b680100000162e430e5a202831c6156b3565b6801000002c5c863b73f02831c6156a5565b68010000058b90cf1e6e02831c615697565b680100000b1721bcfc9a02831c615689565b68010000162e43f4f83102831c61567b565b680100002c5c89d5ec6d02831c61566d565b6801000058b91b5bc9ae02831c61565f565b66800000000000008316615847575b66400000000000008316615835575b66200000000000008316615823575b66100000000000008316615811575b660800000000000083166157ff575b660400000000000083166157ed575b660200000000000083166157db575b660100000000000083161561517b5768010000b17255775c0402831c61517b565b6801000162e525ee054702831c6157ba565b68010002c5cc37da949202831c6157ab565b680100058ba01fb9f96d02831c61579c565b6801000b175effdc76ba02831c61578d565b680100162f3904051fa102831c61577e565b6801002c605e2e8cec5002831c61576f565b68010058c86da1c09ea202831c615760565b6780000000000000008316615957575b6740000000000000008316615945575b6720000000000000008316615933575b6710000000000000008316615921575b670800000000000000831661590f575b67040000000000000083166158fd575b67020000000000000083166158eb575b67010000000000000083161561516c57680100b1afa5abcbed6102831c61516c565b68010163da9fb33356d802831c6158c9565b680102c9a3e778060ee702831c6158b9565b6801059b0d31585743ae02831c6158a9565b68010b5586cf9890f62a02831c615899565b6801172b83c7d517adce02831c615889565b6801306fe0a31b7152df02831c615879565b5077b504f333f9de648480000000000000000000000000000000615869565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b90919060001983820983820291828083109203918083039214615a4557670de0b6b3a76400009081831015615a0e57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90615a955750805115615a6b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615ae0575b615aa6575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15615a9e56fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962005b303881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260075561572e908162000402823960805181613acb015260a051818181610cdb0152613b8c0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a7146127a657508063027b67441461278357806306fdde03146126bb578063081812fc1461269d578063095ea7b3146125965780631400ecec146124f05780631c1cdd4c1461248a5780631e99d5691461246c57806323b872dd1461245557806331df3d481461234957806340e58ee514612048578063425d30dd14611ff257806342842e0e14611fa157806342966c6814611d8f5780634426757014611d685780634857501f14611cee5780634869e12d14611cb15780634cc55e1114611bb657806354c022921461191a5780636352211e146118eb5780636d0cee75146118eb57806370a082311461187b57806375829def146117e15780637cad6cd1146116e35780637de6b1db146114c65780638659c2701461116f578063894e9a0d14610dee5780638f69b99314610d535780639067b67714610cfe5780639188ec8414610cc357806395d89b4114610bb2578063a22cb46514610af4578063a80fc07114610a9d578063ad35efd414610a24578063b2564569146109ce578063b637b8651461096f578063b88d4fde146108e6578063b8a3be66146108b0578063b971302a1461085c578063bc2be1be14610807578063c156a11d146106b1578063c87b56dd1461059d578063cc364f4814610501578063d4dbd20b146104aa578063d511609f14610459578063d975dfed1461040b578063e985e9c5146103b4578063ea5ead1914610386578063eac8f5b81461032f578063f590c176146102ca578063f851a440146102a35763fdd46d601461025d57600080fd5b3461029e57606036600319011261029e576102766128d2565b604435906001600160801b038216820361029e5761029c92610296613ac1565b356134b3565b005b600080fd5b3461029e57600036600319011261029e5760206001600160a01b0360005416604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160a01b0360016040600020015416604051908152f35b503461029e57604036600319011261029e5761029c90356103a56128d2565b6103ae826142bc565b91613108565b3461029e57604036600319011261029e576103cd6128bc565b6103d56128d2565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a576020610448836142bc565b6001600160801b0360405191168152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060026040600020015460801c604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160801b0360036040600020015416604051908152f35b503461029e57602036600319011261029e578035906000602060405161052681612a22565b828152015281600052600960205260ff60016040600020015460a81c161561031a575060005260096020526040806000205464ffffffffff82519161056a83612a22565b818160a01c16835260c81c16602082015261059b825180926020908164ffffffffff91828151168552015116910152565bf35b503461029e5760208060031936011261029e57600082356105bd81613842565b5060446001600160a01b03600854169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106a55760009261062c575b50610628604051928284938452830190612897565b0390f35b9091503d806000833e61063f8183612a6f565b810190828183031261029e5780519067ffffffffffffffff821161029e570181601f8201121561029e57805161067481612a91565b926106826040519485612a6f565b81845284828401011161029e5761069e91848085019101612874565b9038610613565b6040513d6000823e3d90fd5b503461029e57604036600319011261029e578035906106ce6128d2565b916106d7613ac1565b80600052600960205260ff60016040600020015460a81c16156107f1578060005260036020526001600160a01b038060406000205416938433036107ce5761071e836142bc565b6001600160801b0381166107bd575b50818116156107a557826107409161397c565b9081168061075f576024848460405191637e27328960e01b8352820152fd5b840361076757005b6107a1916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107c8908685613108565b3861072d565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602064ffffffffff60406000205460a01c16604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160a01b0360406000205416604051908152f35b503461029e57602036600319011261029e57356000526009602052602060ff60016040600020015460a81c166040519015158152f35b503461029e57608036600319011261029e576109006128bc565b6109086128d2565b906064359267ffffffffffffffff841161029e573660238501121561029e578301359161093483612a91565b926109426040519485612a6f565b808452366024828701011161029e57602081600092602461029c9801838801378501015260443591612f94565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600a6020526106286109ba6040600020612f04565b604051918291602083526020830190612962565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060ff60016040600020015460b01c166040519015158152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a8857610a5e906138f5565b604051906005811015610a7357602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160801b0360026040600020015416604051908152f35b503461029e57604036600319011261029e57610b0e6128bc565b6024359081151580920361029e576001600160a01b0316918215610b825750336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b503461029e57600036600319011261029e576040519060006002549060018260011c92600181168015610cb9575b6020958686108214610ca457508487528693929186908215610c84575050600114610c27575b50610c1392500383612a6f565b610628604051928284938452830190612897565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c6c575050610c13935082010138610c06565b80548389018501528794508693909201918101610c55565b60ff191685820152610c1395151560051b8501019250389150610c069050565b602290634e487b7160e01b6000525260246000fd5b93607f1693610be0565b3461029e57600036600319011261029e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602064ffffffffff60406000205460c81c16604051908152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a8857610d8d906138f5565b9060058210159081610dcb5760028314918215610de0575b8215610db9575b6020836040519015158152f35b909150610dcb57602091143880610dac565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610da5565b503461029e57602036600319011261029e57604051610160810181811067ffffffffffffffff82111761115a576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152610e69612eb1565b61012082015201528035600052600960205260ff60016040600020015460a81c16156111425780356000526009602052604060002090610f39600260405193610eb185612a52565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201612ed0565b610120830152610f4981356138f5565b600581101561112d57600214611121575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600a602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761110c57506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161103490612f04565b82820152610628604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261012081015160406001600160801b039182815116858801528260208201511661016088015201511661018085015201516101a0808401526101c0830190612962565b604190634e487b7160e01b6000525260246000fd5b60006060830152610f5a565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b503461029e576020908160031936011261029e57803567ffffffffffffffff811161029e576111a19036908301612931565b90926111ab613ac1565b6000915b8083106111b857005b6111c3838287612e56565b35926111cd613ac1565b8360005260099081845260ff60019080826040600020015460a81c16156114b057866000528386526040600020818382015460a01c16600014611221576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c611499576112518160005260096020526001600160a01b0360406000205416331490565b156114775761125f8161387d565b94816000528088526112776002604060002001612ed0565b956001600160801b03938488511685831610156114605783600052828a5260406000205460f01c16156114495780848a6112b76112c194838c5116612ae5565b9901511690612ae5565b95826000528189528860406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161783558781169a8b15611430575b600380940198861698896fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9486528160406000205416978896526040600020015416946113798985886146fa565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6113dc575b50505050600191500191906111af565b803b1561029e578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611421575b8080806113cc565b61142a90612a3e565b38611419565b898401600160a01b60ff60a01b19825416179055611327565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b503461029e576020908160031936011261029e5780356114e4613ac1565b806000526009835260ff60016040600020015460a81c16156107f157611509816138f5565b926005841015610a7357838303611531576024838360405191634a5541ef60e01b8352820152fd5b6003840361155057602483836040519163fe19f19f60e01b8352820152fd5b90600284146116cc576115798160005260096020526001600160a01b0360406000205416331490565b156116aa57806000526009825260ff60406000205460f01c1615611693578060005260098252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600383526001600160a01b036040600020541693843b61161f575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b1561029e578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611684575b806115f3565b61168d90612a3e565b8361167e565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b503461029e57602036600319011261029e5780356001600160a01b039081811680910361029e5781600054163381036117b5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101919082116117a0577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b503461029e57602036600319011261029e576117fb6128bc565b600054906001600160a01b039081831633810361184f57506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b503461029e57602036600319011261029e576001600160a01b0361189d6128bc565b1680156118ba576000526020526020604060002054604051908152f35b6024826000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b503461029e57602036600319011261029e5761190960209135613842565b6001600160a01b0360405191168152f35b503461029e5760209060031990828236011261029e5780359167ffffffffffffffff9081841161029e576101208436039182011261029e5761195a613ac1565b60c4840135906022190181121561029e578301828101359082821161029e57602401606082023603811361029e57611993913691612d87565b92835192816119a185612d6f565b946119af6040519687612a6f565b808652601f196119be82612d6f565b018860005b828110611b985750505064ffffffffff90814216956001600160801b0398896119eb82613b1d565b515116828c6119f984613b1d565b5101511685806040611a0a86613b1d565b510151168b01169060405192611a1f84612a06565b83528d8301526040820152611a338a613b1d565b52611a3d89613b1d565b5060019360015b8c8b8d878410611b0957908c8a611a5c818e01612e90565b92611a6960248301612e90565b92611a7660448401612e7c565b946064840135946001600160a01b039586811680910361029e57611b0198611ac198611af698611aa860848a01612ea4565b9481611ab660a48c01612ea4565b976040519d8e6129d3565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e27565b610100820152613b3e565b604051908152f35b8899509084806040611b468a87611b368c9d9e9f9b9c99988b90611b2d828d613b2a565b5151169a613b2a565b5101511694600019890190613b2a565b51015116816040611b57888c613b2a565b5101511601169160405193611b6b85612a06565b84528301526040820152611b7f828d613b2a565b52611b8a818c613b2a565b500190879594939291611a44565b9091929350611ba5612eb1565b82828a0101520190888593926119c3565b503461029e57604036600319011261029e5767ffffffffffffffff90803582811161029e57611be89036908301612931565b9260243590811161029e57611c009036908401612931565b919092611c0b613ac1565b828503611c7b575060005b848110611c1f57005b80611c75611c306001938886612e56565b35611c3c838987612e56565b3560005260036020526001600160a01b0360406000205416611c67611c6285898b612e56565b612e7c565b91611c70613ac1565b6134b3565b01611c16565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57602061044883614754565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57600090611d2c836138f5565b906005821015610dcb5750600203611d4c575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611d3f565b3461029e57600036600319011261029e5760206001600160a01b0360085416604051908152f35b503461029e576020908160031936011261029e57803591611dae613ac1565b826000526009815260ff60016040600020015460a81c1615611f8b57826000526009815260ff60016040600020015460a01c1615611f5b57611def83614223565b15611f375782600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611f2d575b5080611f25575b611f0e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526003835260406000205416918215928315611ed4575b856000526003825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a1611ebe57005b60249160405191637e27328960e01b8352820152fd5b611ef586600052600560205260406000206001600160a01b03198154169055565b8060005284825260406000206000198154019055611e6e565b6024838560405191630da9b01360e01b8352820152fd5b506000611e2e565b9050151538611e27565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b503461029e57611fb0366128fc565b90604051926020840184811067ffffffffffffffff821117611fdd5761029c955060405260008452612f94565b604186634e487b7160e01b6000525260246000fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060ff60016040600020015460a01c166040519015158152f35b503461029e576020908160031936011261029e578035612066613ac1565b80600052600980845260ff60016040600020015460a81c16156123335781600052808452604060002060ff600182015460a01c166000146120b8576024848460405191634a5541ef60e01b8352820152fd5b5460f81c61231c576120e08260005260096020526001600160a01b0360406000205416331490565b156122fa576120ee8261387d565b92826000528185526121066002604060002001612ed0565b936001600160801b03908186511682821610156122e3578460005283875260ff60406000205460f01c16156122cc578661219582847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a61218b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612ae5565b9a01511690612ae5565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156122b2575b0195811695866fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a169a8b91600386528a61225c8d604060002054169d8e96895260016040600020015416966122328b878a6146fa565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61226e57005b843b1561029e576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16122a957005b61029c90612a3e565b60018101600160a01b60ff60a01b198254161790556121db565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b503461029e576003199060203683011261029e5780359167ffffffffffffffff9081841161029e5761014090843603011261029e57612386613ac1565b60405190612393826129d3565b61239e8484016128e8565b82526123ac602485016128e8565b60208301526123bd60448501612aad565b604083015260648401356001600160a01b038116810361029e5760608301526123e8608485016129c6565b60808301526123f960a485016129c6565b60a083015261240a60c48501612d5d565b60c083015260e484013590811161029e578301913660238401121561029e57602093612445611af692611b0195602436928201359101612d87565b60e0840152610104369101612e27565b3461029e5761029c612466366128fc565b91612b14565b3461029e57600036600319011261029e576020600754604051908152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a88576124c4906138f5565b906005821015610dcb57602082158381156124e5575b506040519015158152f35b6001915014826124da565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a576020826000908060005260098352604060002060ff815460f01c1680612584575b61255b575b50506001600160801b0360405191168152f35b61257d92506001600160801b036002612577920154169161387d565b90612ae5565b8280612548565b5060ff600182015460a01c1615612543565b503461029e57604036600319011261029e576125b06128bc565b90602435906125be82613842565b903315158061268a575b8061265c575b61262b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600660205260406000203360005260205260ff60406000205416156125ce565b50336001600160a01b03831614156125c8565b503461029e57602036600319011261029e5761190960209135612ac1565b503461029e57600036600319011261029e57604051906000600190600154918260011c92600181168015612779575b6020958686108214610ca457508487528693929186908215610c8457505060011461271c5750610c1392500383612a6f565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612761575050610c13935082010138610c06565b8054838901850152879450869390920191810161274a565b93607f16936126ea565b3461029e57600036600319011261029e57602060405167016345785d8a00008152f35b823461029e57602036600319011261029e5735907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029e57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561284a575b8115612820575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612819565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612812565b60005b8381106128875750506000910152565b8181015183820152602001612877565b906020916128b081518092818552858086019101612874565b601f01601f1916010190565b600435906001600160a01b038216820361029e57565b602435906001600160a01b038216820361029e57565b35906001600160a01b038216820361029e57565b606090600319011261029e576001600160a01b0390600435828116810361029e5791602435908116810361029e579060443590565b9181601f8401121561029e5782359167ffffffffffffffff831161029e576020808501948460051b01011161029e57565b90815180825260208080930193019160005b828110612982575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612974565b3590811515820361029e57565b610120810190811067ffffffffffffffff8211176129f057604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176129f057604052565b6040810190811067ffffffffffffffff8211176129f057604052565b67ffffffffffffffff81116129f057604052565b610140810190811067ffffffffffffffff8211176129f057604052565b90601f8019910116810190811067ffffffffffffffff8211176129f057604052565b67ffffffffffffffff81116129f057601f01601f191660200190565b35906001600160801b038216820361029e57565b612aca81613842565b5060005260056020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612afe57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612d4557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612d3b575b5080612d33575b612d1c578685526003815282848620541694873315159384612c6c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612c34575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612c065750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612c5582600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612ba2565b91929380915090612cdb575b15612c865790878392612b79565b848887612ca3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612d00575b80612c785750878252600583523384868420541614612c78565b5085825260068352848220338352835260ff8583205416612ce6565b602487855190630da9b01360e01b82526004820152fd5b506001612b5c565b9050151538612b55565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361029e57565b67ffffffffffffffff81116129f05760051b60200190565b929192612d9382612d6f565b604094612da36040519283612a6f565b8195848352602080930191606080960285019481861161029e57925b858410612dcf5750505050505050565b868483031261029e57825190612de482612a06565b612ded85612aad565b8252858501359067ffffffffffffffff8216820361029e57828792838b950152612e18868801612d5d565b86820152815201930192612dbf565b919082604091031261029e57604051612e3f81612a22565b6020808294612e4d816128e8565b84520135910152565b9190811015612e665760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029e5790565b356001600160a01b038116810361029e5790565b35801515810361029e5790565b60405190612ebe82612a06565b60006040838281528260208201520152565b90604051612edd81612a06565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612f1081612d6f565b92604093612f216040519182612a6f565b82815280946020809201926000526020600020906000935b858510612f4857505050505050565b60018481928451612f5881612a06565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612f39565b9190612fa1828285612b14565b803b612fae575b50505050565b61300a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612897565b03906020816000938185885af1908290826130a0575b5050613057578261302f61428c565b80519190826130505760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613088575038808080612fa8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613100575b816130bd60209383612a6f565b810103126130fc5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036130f95750903880613020565b80fd5b5080fd5b3d91506130b0565b92919092613114613ac1565b60009381855260099260209380855260409260ff6001858a20015460a81c161561349d5784885281865260ff6001858a20015460a01c16613486576001600160a01b0391828216928315613476576001600160801b039384861691821561345f57888c5260038a5280888d20541693848314158061344f575b61342c5761319a8a6142bc565b87811685116133fb57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906131cb916142e4565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561320090612ed0565b90808683015116918184818351169201511661321b91612ae5565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966133ce575b8782528552200154169461325e8189886146fa565b8a51908152a480331415806133c4575b61335f575b823314159081613354575b81613349575b506132b8575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613345578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613336575b85948161328a565b61333f90612a3e565b3861332e565b8780fd5b905082141538613284565b833b1515915061327e565b803b156133c0578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16133b1575b50613273565b6133ba90612a3e565b386133ab565b8880fd5b50803b151561326e565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613249565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506134598a614223565b1561318d565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c161561349d578785815281875260ff6001868320015460a01c1661382b576001600160a01b039081851692831561381b576001600160801b03938486169182156138045789845260038b528489852054169485831415806137f4575b6137d1576135588b838e61354483614754565b9289525260028c8820015460801c90612ae5565b87811685116137a05750908b8b928387528282528b808820998b838c54169b6002015460801c90613588916142e4565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556135bd90612ed0565b818086830151169381835116920151166135d691612ae5565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613772575b848852825260018c88200154169461361a818c886146fa565b8b51908152a48133141580613768575b613702575b508133141590816136f7575b816136ec575b50613674575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156136e8578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16136d0575b808061328a565b6136da8691612a3e565b6136e457846136c9565b8480fd5b8280fd5b905081141538613641565b823b1515915061363b565b813b156130f9578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613754575b5061362f565b61376091929a50612a3e565b97388061374e565b50813b151561362a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613601565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506137fe8b614223565b15613531565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115613865575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156138eb5760c81c1611156138d95750600a6020526001604060002054116000146138d0576138cd906143d0565b90565b6138cd906142ff565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c1660001461391c575050600490565b805460f81c613975575460a01c64ffffffffff16421061396f5761393f8161387d565b9060005260096020526001600160801b03806002604060002001541691161060001461396a57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613ab7575b5080613aac575b613a95579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613a5d575b169283613a47575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613a23565b613a7e86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613a1b565b602486885190630da9b01360e01b82526004820152fd5b5081811615156139ba565b90501515386139b3565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613af357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612e665760200190565b8051821015612e665760209160051b010190565b90613b606001600160801b0360408401511660206101008501510151906145b0565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141f957815180156141cf577f0000000000000000000000000000000000000000000000000000000000000000811161419e575064ffffffffff6040613bc384613b1d565b510151168110156141475750600090819082815184905b8082106140b6575050505064ffffffffff421664ffffffffff82168110156140765750506001600160801b031680820361403f575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613d768951996000198b0190613b2a565b51015160c81b169560f01b16911617171717845560005b818110613f6d575050600185016007556001600160a01b036020830151168015612d4557613dc3866001600160a01b039261397c565b16613f3c57613dee6001600160a01b036060840151166001600160801b038351169030903390614689565b6001600160801b0360208201511680613f0c575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613f01613ee260808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613e8b8c612a22565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612962565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613f36906001600160a01b036060850151166001600160a01b036101008601515116903390614689565b38613e02565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613f8a8160e0870151613b2a565b518254680100000000000000008110156129f05760018101808555811015612e6657600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613d8d565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936140da906001600160801b036140d18588613b2a565b515116906142e4565b9364ffffffffff8060406140ee8685613b2a565b5101511694168085111561410a57506001849301909291613bda565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061415884613b1d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614268575b5050821561425657505090565b9091506142633392612ac1565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614249565b3d156142b7573d9061429d82612a91565b916142ab6040519384612a6f565b82523d6000602084013e565b606090565b6138cd906142c981614754565b90600052600960205260026040600020015460801c90612ae5565b9190916001600160801b0380809416911601918211612afe57565b64ffffffffff614334600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166147cf565b91808252600a602052604082208054156143bc5790829167ffffffffffffffff935261438e602083205482845260096020526143896001600160801b03968760026040882001541696879360801c16906148bf565b61492d565b9283136143a45750506143a090614a17565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff80421660008381526009602052604091828220908351916143f683612a52565b80549661012061447c60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612ed0565b94019384528452600a602052614493858520612f04565b91849680876144a186613b1d565b5101511692828288955b161061457a57509161452f6143899284888161453498976001600160801b039e8f6144d6898c613b2a565b5151169d8e9a67ffffffffffffffff60206144f18c84613b2a565b510151169984836145028385613b2a565b510151169650801561456e5761451e9293506000190190613b2a565b5101511680925b03169203166147cf565b6148bf565b92831361454d5750506145478391614a17565b16011690565b5160200151929392831692841683101591506145699050575090565b905090565b50505051168092614525565b8093986001600160801b0390816145918c89613b2a565b51511601169801928282808a6145a7888a613b2a565b510151166144ab565b919091604051906145c082612a22565b600091828152826020820152936001600160801b039283831691821561466a5767016345785d8a000080821161463357506145fc8591846155df565b166020870192818452111561461f5750908261461a92511690612ae5565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061467e82612a22565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176129f0576146f892604052614a53565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146f89161474f606483612a6f565b614a53565b80600052600960205261476d6002604060002001612ed0565b816000526009602052604060002060ff600182015460a01c166000146147a057506001600160801b039150602001511690565b5460f81c6147b257506138cd9061387d565b6138cd91506001600160801b036040818351169201511690612ae5565b600160ff1b8082149081156148b5575b5061488b57600081121561488257614808816000035b600084121561487b578360000390614aef565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614844576000199118131561483e5790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614aef565b614808816147f5565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386147df565b806148da57506148d557670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146149275750806148ff575050670de0b6b3a764000090565b670de0b6b3a764000081146149235761491e906143896138cd93614be9565b614d2b565b5090565b91505090565b600160ff1b808214908115614a0d575b506149e35760008112156149da57614966816000035b60008412156149d35783600003906155df565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161499c576000199118131561483e5790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906155df565b61496681614953565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b905082143861493d565b60008112614a225790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614a7e600080836020829551910182875af1614a7761428c565b908461568e565b908151918215159283614ac7575b505050614a965750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b8192935090602091810103126130fc5760200151908115918215036130f95750388080614a8c565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614bab5782851015614b6f57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614bb9570490565b634e487b7160e01b600052601260045260246000fd5b8015614bb9576ec097ce7bc90715b34b9f10000000000590565b80600080831315614cfa57670de0b6b3a764000092838112614cd757506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ccb57506706f05b59d3b20000905b848213614c9f5750505050500290565b808391020590671bc16d674ec80000821215614cbe575b831d90614c8f565b8091950194831d90614cb6565b93505093925050020290565b6000199392508015614bb9576ec097ce7bc90715b34b9f10000000000591614c0a565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614d5a5768033dd1780914b9711419811261396f57614d5190600003614d2b565b6138cd90614bcf565b680a688906bd8affffff81136155ae57670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615491575b66ff0000000000008316615389575b65ff00000000008316615289575b64ff000000008316615191575b63ff00000083166150a1575b62ff00008316614fb9575b61ff008316614ed9575b60ff8316614e02575b02911c60bf031c90565b60808316614ec7575b838316614eb5575b60208316614ea3575b60108316614e91575b60088316614e7f575b60048316614e6d575b60028316614e5b575b6001831615614df8576801000000000000000102831c614df8565b6801000000000000000102831c614e40565b6801000000000000000302831c614e37565b6801000000000000000602831c614e2e565b6801000000000000000b02831c614e25565b6801000000000000001602831c614e1c565b6801000000000000002c02831c614e13565b6801000000000000005902831c614e0b565b6180008316614fa7575b6140008316614f95575b6120008316614f83575b6110008316614f71575b6108008316614f5f575b6104008316614f4d575b6102008316614f3b575b610100831615614def57680100000000000000b102831c614def565b6801000000000000016302831c614f1f565b680100000000000002c602831c614f15565b6801000000000000058c02831c614f0b565b68010000000000000b1702831c614f01565b6801000000000000162e02831c614ef7565b68010000000000002c5d02831c614eed565b680100000000000058b902831c614ee3565b62800000831661508f575b62400000831661507d575b62200000831661506b575b621000008316615059575b620800008316615047575b620400008316615035575b620200008316615023575b62010000831615614de5576801000000000000b17202831c614de5565b680100000000000162e402831c615006565b6801000000000002c5c802831c614ffb565b68010000000000058b9102831c614ff0565b680100000000000b172102831c614fe5565b68010000000000162e4302831c614fda565b680100000000002c5c8602831c614fcf565b6801000000000058b90c02831c614fc4565b6380000000831661517f575b6340000000831661516d575b6320000000831661515b575b63100000008316615149575b63080000008316615137575b63040000008316615125575b63020000008316615113575b6301000000831615614dda5768010000000000b1721802831c614dda565b6801000000000162e43002831c6150f5565b68010000000002c5c86002831c6150e9565b680100000000058b90c002831c6150dd565b6801000000000b17217f02831c6150d1565b680100000000162e42ff02831c6150c5565b6801000000002c5c85fe02831c6150b9565b68010000000058b90bfc02831c6150ad565b6480000000008316615277575b6440000000008316615265575b6420000000008316615253575b6410000000008316615241575b640800000000831661522f575b640400000000831661521d575b640200000000831661520b575b640100000000831615614dce57680100000000b17217f802831c614dce565b68010000000162e42ff102831c6151ec565b680100000002c5c85fe302831c6151df565b6801000000058b90bfce02831c6151d2565b68010000000b17217fbb02831c6151c5565b6801000000162e42fff002831c6151b8565b68010000002c5c8601cc02831c6151ab565b680100000058b90c0b4902831c61519e565b658000000000008316615377575b654000000000008316615365575b652000000000008316615353575b651000000000008316615341575b65080000000000831661532f575b65040000000000831661531d575b65020000000000831661530b575b65010000000000831615614dc1576801000000b17218355102831c614dc1565b680100000162e430e5a202831c6152eb565b6801000002c5c863b73f02831c6152dd565b68010000058b90cf1e6e02831c6152cf565b680100000b1721bcfc9a02831c6152c1565b68010000162e43f4f83102831c6152b3565b680100002c5c89d5ec6d02831c6152a5565b6801000058b91b5bc9ae02831c615297565b6680000000000000831661547f575b6640000000000000831661546d575b6620000000000000831661545b575b66100000000000008316615449575b66080000000000008316615437575b66040000000000008316615425575b66020000000000008316615413575b6601000000000000831615614db35768010000b17255775c0402831c614db3565b6801000162e525ee054702831c6153f2565b68010002c5cc37da949202831c6153e3565b680100058ba01fb9f96d02831c6153d4565b6801000b175effdc76ba02831c6153c5565b680100162f3904051fa102831c6153b6565b6801002c605e2e8cec5002831c6153a7565b68010058c86da1c09ea202831c615398565b678000000000000000831661558f575b674000000000000000831661557d575b672000000000000000831661556b575b6710000000000000008316615559575b6708000000000000008316615547575b6704000000000000008316615535575b6702000000000000008316615523575b670100000000000000831615614da457680100b1afa5abcbed6102831c614da4565b68010163da9fb33356d802831c615501565b680102c9a3e778060ee702831c6154f1565b6801059b0d31585743ae02831c6154e1565b68010b5586cf9890f62a02831c6154d1565b6801172b83c7d517adce02831c6154c1565b6801306fe0a31b7152df02831c6154b1565b5077b504f333f9de6484800000000000000000000000000000006154a1565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461567d57670de0b6b3a7640000908183101561564657947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906156cd57508051156156a357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615718575b6156de575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156156d656fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003e757601f196001600160401b03601f62004cd43881900382810185168601919084831187841017620003ec57808792606094604052833981010312620003e75783516001600160a01b03928382169291839003620003e7576020918287015196858816809803620003e75760400151948516809503620003e7576200008962000402565b90601c82527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000084830152620000bd62000402565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b8582015230608052600080546001600160a01b031990811688178255600180548216909b178b5596817fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38351858111620003d35760039485548c81811c91168015620003c8575b89821014620003b45790818684931162000361575b508890868311600114620002f8578492620002ec575b505060001982871b1c1916908b1b1784555b8151948511620002d8576004958654998b8b811c9b168015620002cd575b828c1014620002ba57848b1162000271575b869798999a50819487116001146200020a57505093620001fe575b505082871b92600019911b1c19161790555b600a541617600a556009556040516148b1908162000423823960805181613aba0152f35b015191503880620001c8565b8883528183208c9890969594939116915b8282106200025757505085116200023c575b50505050811b019055620001da565b01519060f884600019921b161c19169055388080806200022d565b8484015187558c989096019593840193908101906200021b565b87835281832085880160051c81019b838910620002af575b860160051c019a8c905b8c8110620002a3575050620001ad565b848155018c9062000293565b909b508b9062000289565b634e487b7160e01b835260228852602483fd5b9a607f169a6200019b565b634e487b7160e01b81526041600452602490fd5b0151905038806200016b565b908c8e9416918886528a862092865b8c82821062000341575050841162000328575b505050811b0184556200017d565b015160001983891b60f8161c191690553880806200031a565b91929395968291958786015181550195019301908f959493929162000307565b9091508684528884208680850160051c8201928b8610620003aa575b918f91869594930160051c01915b8281106200039b57505062000155565b8681558594508f91016200038b565b925081926200037d565b634e487b7160e01b84526022600452602484fd5b90607f169062000140565b634e487b7160e01b82526041600452602482fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b03811183821017620003ec5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146130d15750806306fdde031461300d578063081812fc14612fee578063095ea7b314612ef55780631400ecec14612e555780631c1cdd4c14612df05780631e99d56914612dd257806323b872dd14612dba57806339a73c0314612d7957806340e58ee514612b05578063425d30dd14612ab457806342842e0e14612a6457806342966c681461288957806344267570146128625780634857501f146127ec5780634869e12d146127b15780634cc55e111461233357806353b15727146122145780635fe3b567146121ed5780636352211e146121bd5780636d0cee75146121bd57806370a082311461214d57806375829def146120ba578063780a82c81461206d5780637cad6cd114611f9c5780637de6b1db14611d755780638659c27014611a26578063894e9a0d146117375780638bad38dd146116ba5780638f69b9931461161e5780639067b677146115ce57806395d89b41146114bf578063a22cb46514611402578063a6202bf214611305578063a80fc071146112b3578063ab167ccc14611164578063ad35efd414611102578063b2564569146110b1578063b88d4fde14611024578063b8a3be6614610fef578063b971302a14610fa0578063bc063e1a14610f7d578063bc2be1be14610f2d578063c156a11d14610a91578063c87b56dd14610975578063cc364f48146108aa578063d4dbd20b14610858578063d511609f1461080c578063d975dfed146107c0578063e985e9c51461076b578063ea5ead1914610743578063eac8f5b8146106f1578063f590c1761461068f578063f851a440146106695763fdd46d601461027e57600080fd5b34610666576060366003190112610666576004359061029b613200565b916102a461335d565b926102ad613ab0565b818352600b9360209185835260ff600160408720015460a81c161561064f5783855285835260ff600160408720015460a01c16610637576001600160a01b039182821692831561060d576001600160801b03938483169081156105f557878952600587528260408a2054169283821415806105e5575b6105c1576103308961437b565b878116841161058f575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610364916143a6565b858d5284845260408d20600201906103979082906001600160801b036001600160801b031983549260801b169116179055565b6103a090613654565b908084830151169181808251169160400151166103bc91613397565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610560575b848c528252600160408c2001541694610401818a886142ef565b604051908152a48033141580610556575b6104e8575b8333141590816104dd575b816104d2575b5061045c575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104b6575b808061042e565b6104bf9061327c565b6104ca5782386104af565b8280fd5b8380fd5b905083141538610428565b843b15159150610422565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161053e575b5050610417565b6105479061327c565b610552578438610537565b8480fd5b50803b1515610412565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103e7565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105ef89613b0c565b15610323565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b50346106665780600319360112610666576001600160a01b036020915416604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da578160409160209352600b8352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760016040836001600160a01b039360209552600b855220015416604051908152f35b50346106665760403660031901126106665760043590610761613200565b916102a48161437b565b5034610666576040366003190112610666576107856131ea565b604061078f613200565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb60209161437b565b6001600160801b0360405191168152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408260029260209452600b845220015460801c604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760036040836001600160801b039360209552600b855220015416604051908152f35b5034610666576020908160031936011261066657600435916108ca613635565b50828252600b815260ff600160408420015460a81c161561095e576060928252600b815264ffffffffff9182604082205460a01c1692600c8352604081818420541692600b8552205460c81c169160405193610925856132ad565b8452830152604082015261095c60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043561099481613809565b50826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a85578093610a04575b5050610a006040519282849384528301906131c5565b0390f35b909192503d8082843e610a17818461331f565b8201918381840312610a815780519067ffffffffffffffff82116104ca570182601f82011215610a8157805191610a4d83613341565b93610a5b604051958661331f565b838552858484010111610666575090610a79918480850191016131a2565b9038806109ea565b5080fd5b604051903d90823e3d90fd5b503461066657604036600319011261066657600435610aae613200565b610ab6613ab0565b818352600b9060209082825260ff600160408720015460a81c161561064f57838552600582526001600160a01b03918260408720541693843303610f0e57610afd8661437b565b906001600160801b039081831680158015610b9d575b50505050505081811615610b855783610b2b9161396b565b90811680610b4b5760248460405190637e27328960e01b82526004820152fd5b8203610b55578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610ba5613ab0565b898b5282865260ff600160408d20015460a81c1615610ef757898b5282865260ff600160408d20015460a01c16610edf57881561060d57610ec757888a52600585528660408b205416918289141580610eb7575b610e9357610c068a61437b565b8481168311610e615750908a949392918a86528087526040862093610c70610c398760028d89541698015460801c6143a6565b8d8952838a52610c6b600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b613654565b90610c8c818a8401511692826040818351169201511690613397565b161115610e32575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cd38186886142ef565b604051908152a48033141580610e28575b610dbe575b813314159081610db3575b81610da8575b50610d37575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b13565b803b156104ca57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d90575b80610d00565b610d999061327c565b610da4578538610d8a565b8580fd5b905081141538610cfa565b823b15159150610cf4565b803b156104ce57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e14575b5050610ce9565b610e1d9061327c565b6104ce578338610e0d565b50803b1515610ce4565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c94565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ec18a613b0c565b15610bf9565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610666578060031936011261066657602060405167016345785d8a00008152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da576040826001600160a01b039260209452600b8452205416604051908152f35b50346106665760203660031901126106665760ff600160406020936004358152600b855220015460a81c166040519015158152f35b50346106665760803660031901126106665761103e6131ea565b611046613200565b906064359067ffffffffffffffff82116104ce57366023830112156104ce578160040135928461107585613341565b93611083604051958661331f565b8585523660248783010111610a8157856110ae9660246020930183880137850101526044359161369c565b80f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460b01c166040519015158152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5761113b906138e4565b60405190600581101561115057602092508152f35b602483634e487b7160e01b81526021600452fd5b5034610666576101403660031901126106665761117f613ab0565b611187613635565b9064ffffffffff8042168084528161119d613688565b16156112ac5781806111ad613688565b8301165b16602085015260e4359082821682036112a75701166040830152600435916001600160a01b03918284168094036112a757602435908382168092036112a757604435906001600160801b0382168092036112a757606435908582168092036106665750608435918215158093036112a75760a435938415158095036112a7576040519761123d89613290565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126112a7576040519161127783613303565b6101043591821682036112a7578261129f9260209452610124358482015260e0820152613b75565b604051908152f35b600080fd5b81836111b1565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760026040836001600160801b039360209552600b855220015416604051908152f35b50346106665760203660031901126106665761131f6131ea565b6001600160a01b03808354163381036113d9575081169081835260026020526001600160801b036040842054169081156113a85781611379918486526002602052604086206001600160801b0319815416905533906142ef565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106665760403660031901126106665761141c6131ea565b602435908115158092036112a7576001600160a01b031690811561148e5733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657806003193601126106665760405190806004549160018360011c92600185169485156115c4575b60209586861081146115b05785885287949392918790821561158e575050600114611534575b50506115209250038361331f565b610a006040519282849384528301906131c5565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b85831061157657505061152093508201013880611512565b8054838901850152879450869390920191810161155e565b925093505061152094915060ff191682840152151560051b8201013880611512565b602483634e487b7160e01b81526022600452fd5b93607f16936114ec565b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57611657906138e4565b906005821015908161169857600283149182156116ac575b8215611683575b6020836040519015158152f35b90915061169857506004602091143880611676565b80634e487b7160e01b602492526021600452fd5b50600383149150600061166f565b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d9575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b50346106665760203660031901126106665780610140604051611759816132c9565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152611795613635565b61012082015201526004358152600b60205260ff600160408320015460a81c1615611a0e576004358152600b60205260408120906118636002604051936117db856132e6565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613654565b6101208301526118746004356138e4565b60058110156119fa576101406101a093600264ffffffffff93146119ef575b6101208101518360406001600160a01b0360a085015116966004358152600c6020522054169084604084015116606084015115159661010085015115159160c086015115159060e08701511515926001600160a01b038851169a60808b60208b015116990151151590604051996119098b6132c9565b8d8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152610100840152610120830152828201526040519384528260208201511660208501526040810151151560408501526060810151151560608501526001600160a01b0360808201511660808501528260a08201511660a085015260c0810151151560c085015260e0810151151560e085015261010081015115156101008501526119e4610120820151610120860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b015116610180820152f35b836060820152611893565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461066657602080600319360112610a815760043567ffffffffffffffff81116104ca57611a5990369060040161324b565b9190611a63613ab0565b83925b808410611a71578480f35b611a7c84828461360f565b3593611a86613ab0565b848652600b80855260ff90600190828260408b20015460a81c1615611d5e57878952808752604089208281015460a01c841615611ad55760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d4657611b0681600052600b6020526001600160a01b0360406000205416331490565b15611d2657611b148161382c565b818a52828952611b29600260408c2001613654565b906001600160801b0395868351168783161015611d0e57838c52848b5260408c205460f01c1615611cf65791818a8c7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b9d878b85611b9360409b879f9e9d9b84905116613397565b9701511690613397565b85835286845287832098895490600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316178b5560038c84169b8c15611cdd575b019b87169b8c6001600160801b03198254161790556001600160a01b03808093169a8b96600589522054169889965260408d2001541694611c228b85886142ef565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611c86575b505050505050600101929190611a66565b813b15610da457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611cc9575b80808080611c75565b611cd29061327c565b610552578438611cc0565b828101600160a01b60ff60a01b19825416179055611be0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461066657602080600319360112610a815760043590611d94613ab0565b818352600b815260ff600160408520015460a81c1615611f8557611db7826138e4565b6005811015611f715760048103611de05760248360405190634a5541ef60e01b82526004820152fd5b60038103611e00576024836040519063fe19f19f60e01b82526004820152fd5b600214611f5957611e2782600052600b6020526001600160a01b0360406000205416331490565b15611f3a57818352600b815260ff604084205460f01c1615611f2257818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b611eca575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104ca57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611f0e575b80611e9b565b611f179061327c565b6104ca578238611f08565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610666576020366003190112610666576004356001600160a01b03908181168091036104ca57818354163381036113d95750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116120595760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da5760408264ffffffffff9260209452600c8452205416604051908152f35b5034610666576020366003190112610666576120d46131ea565b9080546001600160a01b0380821693338503612126576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610666576020366003190112610666576001600160a01b0361216f6131ea565b16801561218c578160409160209352600683522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106665760203660031901126106665760206121dc600435613809565b6001600160a01b0360405191168152f35b503461066657806003193601126106665760206001600160a01b0360015416604051908152f35b5034610666576101603660031901126106665761222f613ab0565b6040519061223c82613290565b6122446131ea565b825261224e613200565b602083015261225b61335d565b60408301526001600160a01b039060643582811681036112a757606084015260843580151581036112a757608084015260a43580151581036112a75760a084015260603660c319011261066657506040516122b5816132ad565b64ffffffffff60c43581811681036112a757825260e43581811681036112a75760208301526101043590811681036112a757604082015260c08301526040610123193601126112a7576040519161230b83613303565b6101243591821682036112a7578261129f9260209452610144358482015260e0820152613b75565b50346106665760403660031901126106665767ffffffffffffffff6004358181116104ca5761236690369060040161324b565b90916024359081116104ce5761238090369060040161324b565b612388613ab0565b80830361277a57845b83811061239c578580f35b6123a781858761360f565b35906123b481868861360f565b35875260056020526001600160a01b036040882054166123d582858761360f565b35906001600160801b03821682036112a7576123ef613ab0565b838952600b60205260ff600160408b20015460a81c161561064f57838952600b60205260ff600160408b20015460a01c1661063757801561060d576001600160801b038216156127625783895260056020526001600160a01b0360408a205416918282141580612752575b61272e576124678561437b565b6001600160801b0381166001600160801b038316116126fe575090899291858452600b60205260408420926124e66001600160a01b0385541694610c6b6124b68560028094015460801c6143a6565b918a8952600b60205260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361250a8160208401511692826040818351169201511690613397565b1611156126cd575b868552600b6020526001600160a01b0360016040872001541661253f6001600160801b03841685836142ef565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126c3575b612659575b83331415908161264e575b81612643575b506125d1575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612391565b823b156104ce57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161262b575b808061259a565b6126349061327c565b61263f578638612624565b8680fd5b905083141538612594565b843b1515915061258e565b803b1561055257604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af16126af575b5050612583565b6126b89061327c565b6105525784386126a8565b50803b151561257e565b868552600b6020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612512565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061275c85613b0c565b1561245a565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106665760203660031901126106665760ff6001604060043593848152600b60205220015460a81c16156106da576107fb6020916143c1565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f855780612827836138e4565b9260058410156119fa57600260209403612848575b50506040519015158152f35b8152600b8352604090205460f01c60ff169050388061283c565b503461066657806003193601126106665760206001600160a01b03600a5416604051908152f35b503461066657602080600319360112610a8157600435906128a8613ab0565b818352600b815260ff600160408520015460a81c1615611f8557818352600b815260ff600160408520015460a01c1615612a33576128e582613b0c565b15611f3a5781600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c16159081612a29575b5080612a21575b612a09577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260058352604060002054169182159283156129ce575b846000526005825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129b6575080f35b60249060405190637e27328960e01b82526004820152fd5b6129ef85600052600760205260406000206001600160a01b03198154169055565b806000526006825260406000206000198154019055612964565b60248360405190630da9b01360e01b82526004820152fd5b506000612924565b905015153861291d565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066657612a7336613216565b60405191602083019383851067ffffffffffffffff861117612a9e576110ae9460405285845261369c565b634e487b7160e01b600052604160045260246000fd5b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57600160408360ff9360209552600b855220015460a01c166040519015158152f35b503461066657602090816003193601126106665760043590612b25613ab0565b818152600b9283815260ff600160408420015460a81c161561095e5782825283815260408220600181015460a01c60ff1615612b735760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611d4657612b9e81600052600b6020526001600160a01b0360406000205416331490565b15611d2657612bac8161382c565b93818452808352612bc260026040862001613654565b916001600160801b0393848451168588161015611f595781865282815260ff604087205460f01c1615611f2257612c06878683611b938a9b838a9c9b9c5116613397565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d5f575b01988716988981546001600160801b0319161790556001600160a01b038096168097600585528760408b205416978893865260408b20600101541693612c928c84876142ef565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612d0e578480f35b823b15610552576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d50575b81818080808480f35b612d599061327c565b81612d47565b60018101600160a01b60ff60a01b19825416179055612c4b565b5034610666576020366003190112610666576001600160801b0360406020926001600160a01b03612da86131ea565b16815260028452205416604051908152f35b5034610666576110ae612dcc36613216565b916133c6565b50346106665780600319360112610666576020600954604051908152f35b503461066657602036600319011261066657600435808252600b60205260ff600160408420015460a81c16156106da57612e29906138e4565b9060058210156116985760208215838115612e4a575b506040519015158152f35b600191501482612e3f565b50346106665760203660031901126106665760043590818152600b60205260ff600160408320015460a81c1615611f8557602091604082828152600b85522060ff815460f01c1680612ee3575b612eba575b50506001600160801b0360405191168152f35b612edc92506001600160801b036002612ed6920154169161382c565b90613397565b3880612ea7565b5060ff600182015460a01c1615612ea2565b503461066657604036600319011261066657612f0f6131ea565b602435612f1b81613809565b33151580612fdb575b80612fb1575b612f815781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600760205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260086020526040842033855260205260ff60408520541615612f2a565b50336001600160a01b0382161415612f24565b50346106665760203660031901126106665760206121dc600435613373565b503461066657806003193601126106665760405190806003549160018360011c92600185169485156130c7575b60209586861081146115b05785885287949392918790821561158e57505060011461306d5750506115209250038361331f565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b8583106130af57505061152093508201013880611512565b80548389018501528794508693909201918101613097565b93607f169361303a565b905034610a81576020366003190112610a81576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104ca57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613178575b811561314e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613147565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613140565b60005b8381106131b55750506000910152565b81810151838201526020016131a5565b906020916131de815180928185528580860191016131a2565b601f01601f1916010190565b600435906001600160a01b03821682036112a757565b602435906001600160a01b03821682036112a757565b60609060031901126112a7576001600160a01b039060043582811681036112a7579160243590811681036112a7579060443590565b9181601f840112156112a75782359167ffffffffffffffff83116112a7576020808501948460051b0101116112a757565b67ffffffffffffffff8111612a9e57604052565b610100810190811067ffffffffffffffff821117612a9e57604052565b6060810190811067ffffffffffffffff821117612a9e57604052565b610160810190811067ffffffffffffffff821117612a9e57604052565b610140810190811067ffffffffffffffff821117612a9e57604052565b6040810190811067ffffffffffffffff821117612a9e57604052565b90601f8019910116810190811067ffffffffffffffff821117612a9e57604052565b67ffffffffffffffff8111612a9e57601f01601f191660200190565b604435906001600160801b03821682036112a757565b61337c81613809565b5060005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116133b057565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156135f75760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c161590816135ed575b50806135e5575b6135ce57868552600581528284862054169487331515938461351e575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876134e6575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036134b85750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61350782600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055613454565b9192938091509061358d575b15613538579087839261342b565b848887613555576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156135b2575b8061352a575087825260078352338486842054161461352a565b5085825260088352848220338352835260ff8583205416613598565b602487855190630da9b01360e01b82526004820152fd5b50600161340e565b9050151538613407565b6024604051633250574960e11b815260006004820152fd5b919081101561361f5760051b0190565b634e487b7160e01b600052603260045260246000fd5b60405190613642826132ad565b60006040838281528260208201520152565b90604051613661816132ad565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112a75790565b91906136a98282856133c6565b803b6136b6575b50505050565b6137126001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906131c5565b03906020816000938185885af1908290826137a8575b505061375f578261373761434b565b80519190826137585760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036137905750388080806136b0565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613801575b816137c56020938361331f565b81010312610a815751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106665750903880613728565b3d91506137b8565b8060005260056020526001600160a01b03604060002054169081156129b6575090565b600090808252600c60205264ffffffffff918260408220541642106138de57600b6020526040812092835490808260c81c1691824210156138c85761387d9394955060a01c16809103904203614682565b90828152600b6020526001600160801b03926138a3846002604085200154168094614762565b9283116138b05750501690565b60029350604092508152600b60205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b80600052600b602052604060002060ff600182015460a01c1660001461390b575050600490565b805460f81c613964575460a01c64ffffffffff16421061395e5761392e8161382c565b90600052600b6020526001600160801b03806002604060002001541691161060001461395957600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613aa6575b5080613a9b575b613a84579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613a4c575b169283613a36575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613a12565b613a6d86600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613a0a565b602486885190630da9b01360e01b82526004820152fd5b5081811615156139a9565b90501515386139a2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ae257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260056020526001600160a01b038060408420541692833314938415613b51575b50508215613b3f57505090565b909150613b4c3392613373565b161490565b60ff9294509060409181526008602052818120338252602052205416913880613b32565b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156142e3576000906142af575b613bf691506001600160801b0360408501511690602060e086015101519161443c565b916001600160801b0383511660c082015190156142855764ffffffffff8151161561425b5764ffffffffff81511690604081019164ffffffffff835116908181101561421b57505064ffffffffff60208201511680151580614209575b6141c75750602064ffffffffff9101511664ffffffffff825116908181101561418757505064ffffffffff8042169151169081811015614147575050600954926001600160801b0381511660405190613cab826132ad565b815260006020820152600060408201526001600160a01b0360608401511660c08401519064ffffffffff604083015116608086015115159060a087015115159064ffffffffff6001600160a01b038951169551169060405195613d0d876132e6565b8652602086019182526040860190815260608601938452608086016000815260a0870195865260c08701946000865260e08801936001855261010089019586526101208901998a528d600052600b6020527fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000078ffffffffff00000000000000000000000000000000000000006001600160a01b0360406000209d5116945160a01b16965160c81b169351151560f01b169351151560f81b16931717171785556001600160a01b03600186019451167fffffffffffffffffff000000000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000075ff00000000000000000000000000000000000000000074ff000000000000000000000000000000000000000088549751151560a01b169451151560a81b169451151560b01b1694161717171790556001600160801b036040600360028401945193613ef484865116966001600160801b03199788825416178155856020880151166001600160801b036001600160801b031983549260801b169116179055565b01920151168282541617905564ffffffffff602060c085015101511680614129575b50600185016009556001600160a01b0360608401511660005260026020526001600160801b0380604060002054168160208501511601166001600160a01b036060850151166000526040600020918254161790556001600160a01b0360208301511680156135f757613f90856001600160a01b039261396b565b166140f857613fc56001600160a01b036060840151166001600160801b0380845116816020860151160116903090339061457b565b6001600160801b03604082015116806140c9575b506001600160a01b038251167f075861cbceafeb777e8f15f357121b08f6f3adba387d599bb7b5278ca6192df5610160866001600160a01b03602087015116946140c06001600160a01b03606089015116976080810151151560a082015115159061408a6001600160a01b0360e060c08601519501515116956040519788523360208901526040880190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a086015260c0850152805164ffffffffff90811660e08601526020820151811661010086015260409091015116610120840152565b610140820152a4565b6140f2906001600160a01b036060850151166001600160a01b0360e0860151511690339061457b565b38613fd9565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600c60205260406000209064ffffffffff1982541617905538613f16565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b81516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508064ffffffffff8351161015613c53565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d6020116142db575b816142c96020938361331f565b810103126112a757613bf69051613bd3565b3d91506142bc565b6040513d6000823e3d90fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526143499161434460648361331f565b6145e6565b565b3d15614376573d9061435c82613341565b9161436a604051938461331f565b82523d6000602084013e565b606090565b6143a390614388816143c1565b90600052600b60205260026040600020015460801c90613397565b90565b9190916001600160801b03808094169116019182116133b057565b80600052600b6020526143da6002604060002001613654565b81600052600b602052604060002060ff600182015460a01c1660001461440d57506001600160801b039150602001511690565b5460f81c61441f57506143a39061382c565b6143a391506001600160801b036040818351169201511690613397565b909291614447613635565b936001600160801b03928381169182156145535767016345785d8a000080821161451c578085116144e5575061449185614482819386614762565b16946020890195865284614762565b1691846144a86040890194808652828751166143a6565b1610156144cf576144c18491826144ca95511690613397565b91511690613397565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050509050604051614566816132ad565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612a9e57614349926040525b6001600160a01b031690614611600080836020829551910182875af161460a61434b565b9084614811565b90815191821515928361465a575b5050506146295750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a81576020015190811591821503610666575038808061461f565b670de0b6b3a764000091600019838309928083029283808610950394808603951461473e578285101561470257908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b50508092501561474c570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461480057670de0b6b3a764000090818310156147c957947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614850575080511561482657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061489b575b614861575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561485956fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f6200496b3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360075561458e9081620003dd8239608051816139100152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f2757508063027b674414612f0457806306fdde0314612e3f578063081812fc14612e20578063095ea7b314612d275780631400ecec14612c875780631c1cdd4c14612c225780631e99d56914612c0457806323b872dd14612bec57806340e58ee51461296e578063425d30dd1461291d57806342842e0e146128cd57806342966c68146126f257806344267570146126cb5780634857501f146126555780634869e12d1461261a5780634cc55e111461218a57806353b157271461206b5780636352211e1461203b5780636d0cee751461203b57806370a0823114611fcb57806375829def14611f38578063780a82c814611eeb5780637cad6cd114611df15780637de6b1db14611bca5780638659c27014611879578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613056565b916102786131b3565b92610281613906565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614079565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134aa565b906103b1818684015116928260408183511692015116906131ed565b161115610532575b848c528252600160408c20015416946103d3818a886140a4565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b610491906130d2565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b610519906130d2565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613962565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613056565b9161027881614079565b503461064c57604036600319011261064c5761076b613040565b6040610775613056565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614079565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b061348b565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613103565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a8161365f565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061301b565b0390f35b909192503d8082843e6109fd8184613175565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a3383613197565b93610a416040519586613175565b83855285848401011161064c575090610a5f91848085019101612ff8565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613056565b610a9c613906565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae386614079565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137c1565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613906565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a614079565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a84015116928260408183511692015116906131ed565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140a4565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c906130d2565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e00906130d2565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613962565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613040565b61101a613056565b906064359067ffffffffffffffff82116104a057366023830112156104a0578160040135928461104985613197565b936110576040519586613175565b8585523660248783010111610a675785611082966024602093018388013785010152604435916134f2565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061373a565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613906565b61115b61348b565b9064ffffffffff804216808452816111716134de565b16156112805781806111816134de565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b5760405197611211896130e6565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613159565b61010435918216820361127b57826112739260209452610124358482015260e08201526139cb565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613040565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f792500383613175565b6109e660405192828493845283019061301b565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e9061373a565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101406040516115b38161311f565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201526115ef61348b565b61012082015201526004358152600960205260ff600160408320015460a81c1615611861576004358152600960205260408120906116bd6002604051936116358561313c565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134aa565b6101208301526116ce60043561373a565b600581101561184d576101406101a093600264ffffffffff9314611842575b6101208101518360406001600160a01b0360a085015116966004358152600a6020522054169084604084015116606084015115159661010085015115159160c086015115159060e08701511515926001600160a01b038851169a60808b60208b015116990151151590604051996117638b61311f565b8d8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152610100840152610120830152828201526040519384528260208201511660208501526040810151151560408501526060810151151560608501526001600160a01b0360808201511660808501528260a08201511660a085015260c0810151151560c085015260e0810151151560e0850152610100810151151561010085015261012081015160406001600160801b0391828151166101208801528260208201511685880152015116610160850152015116610180820152f35b8360608201526116ed565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118ac9036906004016130a1565b91906118b6613906565b83925b8084106118c4578480f35b6118cf848284613465565b35936118d9613906565b848652600980855260ff90600190828260408b20015460a81c1615611bb357878952808752604089208281015460a01c8416156119285760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611b9b576119598160005260096020526001600160a01b0360406000205416331490565b15611b7b5761196781613682565b818a5282895261197c600260408c20016134aa565b906001600160801b0395868351168783161015611b6357838c52848b5260408c205460f01c1615611b4b5791818a6119cd85898f9a9998966119c38c9983879351166131ed565b95015116906131ed565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b32575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611a778b85886140a4565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611adb575b5050505050506001019291906118b9565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b1e575b80808080611aca565b611b27906130d2565b610524578438611b15565b818601600160a01b60ff60a01b19825416179055611a32565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611be9613906565b8183526009815260ff600160408520015460a81c1615611dda57611c0c8261373a565b6005811015611dc65760048103611c355760248360405190634a5541ef60e01b82526004820152fd5b60038103611c55576024836040519063fe19f19f60e01b82526004820152fd5b600214611dae57611c7c8260005260096020526001600160a01b0360406000205416331490565b15611d8f578183526009815260ff604084205460f01c1615611d7757818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d1f575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d63575b80611cf0565b611d6c906130d2565b61049c578238611d5d565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ec2575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611eae5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f52613040565b9080546001600160a01b0380821693338503611fa4576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03611fed613040565b16801561200a578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061205a60043561365f565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c57612086613906565b60405190612093826130e6565b61209b613040565b82526120a5613056565b60208301526120b26131b3565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c575060405161210c81613103565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161216283613159565b61012435918216820361127b57826112739260209452610144358482015260e08201526139cb565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121bd9036906004016130a1565b90916024359081116104a0576121d79036906004016130a1565b6121df613906565b8083036125e357845b8381106121f3578580f35b6121fe818587613465565b359061220b818688613465565b35875260036020526001600160a01b0360408820541661222c828587613465565b35906001600160801b038216820361127b57612246613906565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125cb5783895260036020526001600160a01b0360408a2054169182821415806125bb575b612597576122be85614079565b6001600160801b0381166001600160801b038316116125675750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b038111610561579061234f8c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361237381602084015116928260408183511692015116906131ed565b161115612536575b86855260096020526001600160a01b036001604087200154166123a86001600160801b03841685836140a4565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061252c575b6124c2575b8333141590816124b7575b816124ac575b5061243a575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016121e8565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612494575b8080612403565b61249d906130d2565b6124a857863861248d565b8680fd5b9050831415386123fd565b843b151591506123f7565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612518575b50506123ec565b612521906130d2565b610524578438612511565b50803b15156123e7565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561237b565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125c585613962565b156122b1565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614100565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611dda57806126908361373a565b92600584101561184d576002602094036126b1575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126a5565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612711613906565b8183526009815260ff600160408520015460a81c1615611dda578183526009815260ff600160408520015460a01c161561289c5761274e82613962565b15611d8f5781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081612892575b508061288a575b612872577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612837575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161281f575080f35b60249060405190637e27328960e01b82526004820152fd5b61285885600052600560205260406000206001600160a01b03198154169055565b8060005260048252604060002060001981540190556127cd565b60248360405190630da9b01360e01b82526004820152fd5b50600061278d565b9050151538612786565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c576128dc3661306c565b60405191602083019383851067ffffffffffffffff86111761290757611082946040528584526134f2565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c576004359061298e613906565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff16156129dc5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611b9b57612a078160005260096020526001600160a01b0360406000205416331490565b15611b7b57612a1581613682565b93818452808352612a2b600260408620016134aa565b916001600160801b0393848451168588161015611dae5781865282815260ff604087205460f01c1615611d7757612a79878683612a6f8a9b838a9c9b9c51166131ed565b97015116906131ed565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612bd2575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b058c84876140a4565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612b81578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bc3575b81818080808480f35b612bcc906130d2565b81612bba565b60018101600160a01b60ff60a01b19825416179055612abe565b503461064c57611082612bfe3661306c565b9161321c565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c5b9061373a565b90600582101561156f5760208215838115612c7c575b506040519015158152f35b600191501482612c71565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611dda57602091604082828152600985522060ff815460f01c1680612d15575b612cec575b50506001600160801b0360405191168152f35b612d0e92506001600160801b036002612d089201541691613682565b906131ed565b3880612cd9565b5060ff600182015460a01c1615612cd4565b503461064c57604036600319011261064c57612d41613040565b602435612d4d8161365f565b33151580612e0d575b80612de3575b612db35781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d5c565b50336001600160a01b0382161415612d56565b503461064c57602036600319011261064c57602061205a6004356131c9565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612efa575b602095868610811461148757858852879493929187908215611465575050600114612ea05750506113f792500383613175565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612ee25750506113f7935082010138806113e9565b80548389018501528794508693909201918101612eca565b93607f1693612e6d565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115612fce575b8115612fa4575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612f9d565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612f96565b60005b83811061300b5750506000910152565b8181015183820152602001612ffb565b9060209161303481518092818552858086019101612ff8565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161290757604052565b610100810190811067ffffffffffffffff82111761290757604052565b6060810190811067ffffffffffffffff82111761290757604052565b610160810190811067ffffffffffffffff82111761290757604052565b610140810190811067ffffffffffffffff82111761290757604052565b6040810190811067ffffffffffffffff82111761290757604052565b90601f8019910116810190811067ffffffffffffffff82111761290757604052565b67ffffffffffffffff811161290757601f01601f191660200190565b604435906001600160801b038216820361127b57565b6131d28161365f565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161320657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561344d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613443575b508061343b575b613424578685526003815282848620541694873315159384613374575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761333c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361330e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61335d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132aa565b919293809150906133e3575b1561338e5790878392613281565b8488876133ab576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613408575b806133805750878252600583523384868420541614613380565b5085825260068352848220338352835260ff85832054166133ee565b602487855190630da9b01360e01b82526004820152fd5b506001613264565b905015153861325d565b6024604051633250574960e11b815260006004820152fd5b91908110156134755760051b0190565b634e487b7160e01b600052603260045260246000fd5b6040519061349882613103565b60006040838281528260208201520152565b906040516134b781613103565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b91906134ff82828561321c565b803b61350c575b50505050565b6135686001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061301b565b03906020816000938185885af1908290826135fe575b50506135b5578261358d614049565b80519190826135ae5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036135e6575038808080613506565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613657575b8161361b60209383613175565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c575090388061357e565b3d915061360e565b8060005260036020526001600160a01b036040600020541690811561281f575090565b600090808252600a60205264ffffffffff918260408220541642106137345760096020526040812092835490808260c81c16918242101561371e576136d39394955060a01c168091039042036142c3565b9082815260096020526001600160801b03926136f98460026040852001541680946143a3565b9283116137065750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613761575050600490565b805460f81c6137ba575460a01c64ffffffffff1642106137b45761378481613682565b9060005260096020526001600160801b0380600260406000200154169116106000146137af57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c161590816138fc575b50806138f1575b6138da579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138a2575b16928361388c575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613868565b6138c386600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613860565b602486885190630da9b01360e01b82526004820152fd5b5081811615156137ff565b90501515386137f8565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361393857565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139a7575b5050821561399557505090565b9091506139a233926131c9565b161490565b60ff9294509060409181526006602052818120338252602052205416913880613988565b906139ec6001600160801b03604084015116602060e085015101519061417b565b916001600160801b0383511660c0820151901561401f5764ffffffffff81511615613ff55764ffffffffff81511690604081019164ffffffffff8351169081811015613fb5575050602081019064ffffffffff8251169081151580613fa3575b613f6257505064ffffffffff90511664ffffffffff8251169081811015613f2257505064ffffffffff8042169151169081811015613ee2575050600754926001600160801b0381511660405190613aa282613103565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b048861313c565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613cfc84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613ec4575b50600184016007556001600160a01b03602083015116801561344d57613d4c856001600160a01b03926137c1565b16613e9357613d776001600160a01b036060840151166001600160801b038351169030903390614254565b6001600160801b0360208201511680613e64575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e5b6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613e8d906001600160a01b036060850151166001600160a01b0360e08601515116903390614254565b38613d8b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d1e565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a4c565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614074573d9061405a82613197565b916140686040519384613175565b82523d6000602084013e565b606090565b6140a19061408681614100565b90600052600960205260026040600020015460801c906131ed565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526140fe916140f9606483613175565b614452565b565b80600052600960205261411960026040600020016134aa565b816000526009602052604060002060ff600182015460a01c1660001461414c57506001600160801b039150602001511690565b5460f81c61415e57506140a190613682565b6140a191506001600160801b0360408183511692015116906131ed565b9190916040519061418b82613159565b600091828152826020820152936001600160801b03928383169182156142355767016345785d8a00008082116141fe57506141c78591846143a3565b16602087019281845211156141ea575090826141e5925116906131ed565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061424982613159565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612907576140fe92604052614452565b670de0b6b3a764000091600019838309928083029283808610950394808603951461437f578285101561434357908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b50508092501561438d570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461444157670de0b6b3a7640000908183101561440a57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b03169061447d600080836020829551910182875af1614476614049565b90846144ee565b9081519182151592836144c6575b5050506144955750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c575038808061448b565b9061452d575080511561450357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614578575b61453e575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561453656fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0346200046e57601f6200515138819003918201601f19168301916001600160401b038311848410176200032b578084926080946040528339810103126200046e5780516001600160a01b038082169290918390036200046e5760208101518281168091036200046e5760408201519183831683036200046e5760600151936200008962000473565b90601e82527f5361626c696572205632204c6f636b7570205472616e63686564204e465400006020830152620000be62000473565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052600080546001600160a01b03199081168417825560018054909116909517909455927fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a38051906001600160401b0382116200032b5760035490600182811c9216801562000463575b60208310146200044d5781601f849311620003d8575b50602090601f83116001146200034d5760009262000341575b50508160011b916000199060031b1c1916176003555b80516001600160401b0381116200032b576004918254600181811c9116801562000320575b60208210146200030b579081601f849311620002b3575b50602090601f831160011462000248576000926200023c575b50508160011b916000199060031b1c19161790555b1660018060a01b0319600a541617600a5560a0526001600955604051614cbd908162000494823960805181613f56015260a05181818161303901526140560152f35b015190503880620001e5565b6000858152602081209350601f198516905b8181106200029a575090846001959493921062000280575b505050811b019055620001fa565b015160001960f88460031b161c1916905538808062000272565b929360206001819287860151815501950193016200025a565b909150836000526020600020601f840160051c8101916020851062000300575b90601f859493920160051c01905b818110620002f05750620001cc565b60008155849350600101620002e1565b9091508190620002d3565b602284634e487b7160e01b6000525260246000fd5b90607f1690620001b5565b634e487b7160e01b600052604160045260246000fd5b0151905038806200017a565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9350601f198516905b818110620003bf5750908460019594939210620003a5575b505050811b0160035562000190565b015160001960f88460031b161c1916905538808062000396565b929360206001819287860151815501950193016200037e565b60036000529091507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f840160051c8101916020851062000442575b90601f859493920160051c01905b81811062000432575062000161565b6000815584935060010162000423565b909150819062000415565b634e487b7160e01b600052602260045260246000fd5b91607f16916200014b565b600080fd5b60408051919082016001600160401b038111838210176200032b5760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146133735750806306fdde03146132af578063081812fc14613290578063095ea7b3146131975780631400ecec146130f75780631c1cdd4c146130925780631e99d5691461307457806323b872dd1461305c5780632fe430411461302157806332fbe22b14612ed257806339a73c0314612e9157806340e58ee514612c06578063425d30dd14612bb557806342842e0e14612b7b57806342966c68146129a057806344267570146129795780634857501f146129035780634869e12d146128c85780634cc55e11146124555780635fe3b5671461242e5780636352211e146123fe5780636d0cee75146123fe57806370a082311461238e57806375829def146122fb5780637cad6cd11461222a5780637de6b1db146120035780637f5799f914611fa85780638659c27014611c59578063894e9a0d14611912578063897f362b146116625780638bad38dd146115e55780638f69b993146115495780639067b677146114f957806395d89b41146113ea578063a22cb4651461132d578063a6202bf214611230578063a80fc071146111de578063ad35efd41461117c578063b25645691461112b578063b88d4fde1461109e578063b8a3be6614611069578063b971302a1461101a578063bc063e1a14610ff7578063bc2be1be14610fa7578063c156a11d14610b19578063c87b56dd146109fd578063cc364f4814610965578063d4dbd20b14610913578063d511609f146108c7578063d975dfed1461087b578063e985e9c514610826578063ea5ead1914610744578063eac8f5b8146106f2578063f590c17614610690578063f851a4401461066a5763fdd46d601461028957600080fd5b3461066757606036600319011261066757600435906102a66134a2565b91604435926001600160801b0380851691828603610662576102c6613f4c565b838552600b9560209387855260ff600160408920015460a81c161561064b5785875287855260ff600160408920015460a01c16610633576001600160a01b039081841680156106095781156105f157878952600587528260408a2054169283821415806105e1575b6105bd5761033b89614863565b878116841161058b575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061036f9161488e565b858d5284845260408d20600201908282549160801b6001600160801b031916911617815561039c90613a68565b908084830151169181808251169160400151166103b89161368a565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361055c575b848c528252600160408c20015416946103fd818a886147d7565b604051908152a48033141580610552575b6104e4575b8333141590816104d9575b816104ce575b50610458575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104ca57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16104b2575b808061042a565b6104bb906135ab565b6104c65782386104ab565b8280fd5b8380fd5b905083141538610424565b843b1515915061041e565b803b1561054e57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161053a575b5050610413565b610543906135ab565b61054e578438610533565b8480fd5b50803b151561040e565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103e3565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105eb8961476e565b1561032e565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106675780600319360112610667576001600160a01b036020915416604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db578160409160209352600b8352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760016040836001600160a01b039360209552600b855220015416604051908152f35b503461066757604036600319011261066757600435906107626134a2565b9161076c81614863565b92610775613f4c565b818352600b9360209185835260ff600160408720015460a81c161561080f5783855285835260ff600160408720015460a01c166107f7576001600160a01b0391828216928315610609576001600160801b03938483169081156105f157878952600587528260408a2054169283821415806105e1576105bd5761033b89614863565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106675760403660031901126106675761084061348c565b604061084a6134a2565b926001600160a01b0380931681526008602052209116600052602052602060ff604060002054166040519015158152f35b50346106675760203660031901126106675760ff6001604060043593848152600b60205220015460a81c16156106db576108b6602091614863565b6001600160801b0360405191168152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408260029260209452600b845220015460801c604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760036040836001600160801b039360209552600b855220015416604051908152f35b5034610667576020366003190112610667576004356000602060405161098a816135dc565b8281520152808252600b60205260ff600160408420015460a81c16156106db5760408281928152600b602052205464ffffffffff8251916109ca836135dc565b818160a01c16835260c81c1660208201526109fb825180926020908164ffffffffff91828151168552015116910152565bf35b503461066757602080600319360112610b0957600435610a1c81613c2a565b50826001600160a01b03600a5416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610b0d578093610a8c575b5050610a88604051928284938452830190613467565b0390f35b909192503d8082843e610a9f8184613614565b8201918381840312610b095780519067ffffffffffffffff82116104c6570182601f82011215610b0957805191610ad583613636565b93610ae36040519586613614565b838552858484010111610667575090610b0191848085019101613444565b903880610a72565b5080fd5b604051903d90823e3d90fd5b503461066757604036600319011261066757600435610b366134a2565b610b3e613f4c565b818352600b9060209082825260ff600160408720015460a81c161561080f57838552600582526001600160a01b03918260408720541693843303610f8857610b8586614863565b906001600160801b039081831680158015610c25575b50505050505081811615610c0d5783610bb391613e07565b90811680610bd35760248460405190637e27328960e01b82526004820152fd5b8203610bdd578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c2d613f4c565b898b5282865260ff600160408d20015460a81c1615610f7157898b5282865260ff600160408d20015460a01c16610f5957881561060957610f4157888a52600585528660408b205416918289141580610f31575b610f0d57610c8e8a614863565b8481168311610edb5750908a949392918a86528087526040862093610cea610cc18760028d89541698015460801c61488e565b8d8952838a52600260408a200190836001600160801b031983549260801b169116178155613a68565b90610d06818a840151169282604081835116920151169061368a565b161115610eac575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d4d8186886147d7565b604051908152a48033141580610ea2575b610e38575b813314159081610e2d575b81610e22575b50610db1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b9b565b803b156104c657604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610e0a575b80610d7a565b610e13906135ab565b610e1e578538610e04565b8580fd5b905081141538610d74565b823b15159150610d6e565b803b156104ca57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e8e575b5050610d63565b610e97906135ab565b6104ca578338610e87565b50803b1515610d5e565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610d0e565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f3b8a61476e565b15610c81565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408264ffffffffff9260209452600b8452205460a01c16604051908152f35b5034610667578060031936011261066757602060405167016345785d8a00008152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576040826001600160a01b039260209452600b8452205416604051908152f35b50346106675760203660031901126106675760ff600160406020936004358152600b855220015460a81c166040519015158152f35b5034610667576080366003190112610667576110b861348c565b6110c06134a2565b906064359067ffffffffffffffff82116104ca57366023830112156104ca57816004013592846110ef85613636565b936110fd6040519586613614565b8585523660248783010111610b09578561112896602460209301838801378501015260443591613abd565b80f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57600160408360ff9360209552600b855220015460b01c166040519015158152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576111b590613d80565b6040519060058110156111ca57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760026040836001600160801b039360209552600b855220015416604051908152f35b50346106675760203660031901126106675761124a61348c565b6001600160a01b0380835416338103611304575081169081835260026020526001600160801b036040842054169081156112d357816112a4918486526002602052604086206001600160801b0319815416905533906147d7565b6040519081527fca7a4a65a94ed2f37538814e00e1cd4c41a78261561e3f3794592f11409cf5af60203392a380f35b602483604051907f8410168c0000000000000000000000000000000000000000000000000000000082526004820152fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106675760403660031901126106675761134761348c565b60243590811515809203610662576001600160a01b03169081156113b95733835260086020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757806003193601126106675760405190806004549160018360011c92600185169485156114ef575b60209586861081146114db578588528794939291879082156114b957505060011461145f575b505061144b92500383613614565b610a88604051928284938452830190613467565b90859250600482527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8583106114a157505061144b9350820101388061143d565b80548389018501528794508693909201918101611489565b925093505061144b94915060ff191682840152151560051b820101388061143d565b602483634e487b7160e01b81526022600452fd5b93607f1693611417565b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5760408264ffffffffff9260209452600b8452205460c81c16604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db5761158290613d80565b90600582101590816115c357600283149182156115d7575b82156115ae575b6020836040519015158152f35b9091506115c3575060046020911438806115a1565b80634e487b7160e01b602492526021600452fd5b50600383149150600061159a565b5034610667576020366003190112610667576004356001600160a01b03908181168091036104c65781835416338103611304575060015491816001600160a01b03198416176001556040519216825260208201527fdcb09aef4bf01068924ccce937981cbe59d25ba08380cf941aaaea4e4bd3960d60403392a280f35b5034610667576020906003198281360112610b09576004359167ffffffffffffffff91828411610b095761012084360391820112610b09576116a2613f4c565b60c48401359060221901811215610b095783016004810135928311610b095760248101908360061b80360383136104ca576024906116df86613914565b956116ed6040519788613614565b8652878601920101913683116104ca57905b868383106118fa575050505081519061171782613914565b926117256040519485613614565b828452601f1961173484613914565b0186835b8281106118d65750505064ffffffffff804216936001600160801b03928361175f82613c4d565b51511683808b61176e85613c4d565b5101511688011660405191611782836135dc565b82528a82015261179188613c4d565b5261179b87613c4d565b5060019260015b83811061186d5750505050506117ba85600401613a9c565b916117c760248701613a9c565b916117d4604488016139b7565b6064880135926001600160a01b039081851680950361066757509288959261182598959261185a989561180c60846118659d01613ab0565b948161181a60a48c01613ab0565b976040519d8e61358e565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613962565b610100820152613fa8565b604051908152f35b8089838d8180826118928d6118838e9a8d613c5a565b51511696600019890190613c5a565b51015116916118a1868a613c5a565b510151160116604051916118b4836135dc565b82528d8201526118c4828c613c5a565b526118cf818b613c5a565b50016117a2565b6040516118e2816135dc565b60008152600083820152828289010152018790611738565b604091611907368561392c565b8152019101906116ff565b5034610667576020366003190112610667576060610140604051611935816135bf565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152611970613a49565b61012082015201526004358152600b60205260ff600160408320015460a81c1615611c41576004358152600b602052604081209060405191610140830183811067ffffffffffffffff821117611c2b57611a529160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613a68565b610120830152611a63600435613d80565b6005811015611c1757610140926002611b2f9214611c0c575b6101208101516001600160a01b0360a08301511664ffffffffff60408401511694606084015115159061010085015115159260c086015115159160e08701511515936001600160a01b03885116996080604064ffffffffff60208c015116946004358152600c602052209901511515926040519b611af98d6135bf565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e08601526101008501526101208401526139cb565b82820152610a88604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e081015115156101008501526101008101511515610120850152611bf861012082015183860190604090816001600160801b0391828151168552826020820151166020860152015116910152565b01516101a0808401526101c0830190613532565b826060820152611a7c565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461066757602080600319360112610b095760043567ffffffffffffffff81116104c657611c8c903690600401613501565b9190611c96613f4c565b83925b808410611ca4578480f35b611caf848284613991565b3593611cb9613f4c565b848652600b80855260ff90600190828260408b20015460a81c1615611f9157878952808752604089208281015460a01c841615611d085760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611f7957611d3981600052600b6020526001600160a01b0360406000205416331490565b15611f5957611d4781613c6e565b818a52828952611d5c600260408c2001613a68565b906001600160801b0395868351168783161015611f4157838c52848b5260408c205460f01c1615611f295791818a8c7f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611dd0878b85611dc660409b879f9e9d9b8490511661368a565b970151169061368a565b85835286845287832098895490600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316178b5560038c84169b8c15611f10575b019b87169b8c6001600160801b03198254161790556001600160a01b03808093169a8b96600589522054169889965260408d2001541694611e558b85886147d7565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611eb9575b505050505050600101929190611c99565b813b15610e1e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611efc575b80808080611ea8565b611f05906135ab565b61054e578438611ef3565b828101600160a01b60ff60a01b19825416179055611e13565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57604082611fef92610a889452600c602052206139cb565b604051918291602083526020830190613532565b503461066757602080600319360112610b095760043590612022613f4c565b818352600b815260ff600160408520015460a81c16156122135761204582613d80565b60058110156121ff576004810361206e5760248360405190634a5541ef60e01b82526004820152fd5b6003810361208e576024836040519063fe19f19f60e01b82526004820152fd5b6002146121e7576120b582600052600b6020526001600160a01b0360406000205416331490565b156121c857818352600b815260ff604084205460f01c16156121b057818352600b81526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600583526001600160a01b03604083205416803b612158575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104c657816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af161219c575b80612129565b6121a5906135ab565b6104c6578238612196565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610667576020366003190112610667576004356001600160a01b03908181168091036104c657818354163381036113045750600a5491816001600160a01b0319841617600a556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260095460001981019081116122e75760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b50346106675760203660031901126106675761231561348c565b9080546001600160a01b0380821693338503612367576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610667576020366003190112610667576001600160a01b036123b061348c565b1680156123cd578160409160209352600683522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757602036600319011261066757602061241d600435613c2a565b6001600160a01b0360405191168152f35b503461066757806003193601126106675760206001600160a01b0360015416604051908152f35b50346106675760403660031901126106675767ffffffffffffffff6004358181116104c657612488903690600401613501565b90916024359081116104ca576124a2903690600401613501565b6124aa613f4c565b80830361289157845b8381106124be578580f35b6124c9818587613991565b35906124d6818688613991565b35875260056020526001600160a01b036040882054166124ff6124fa838688613991565b6139b7565b90612508613f4c565b838952600b60205260ff600160408b20015460a81c161561080f57838952600b60205260ff600160408b20015460a01c166107f7578015610609576001600160801b038216156128795783895260056020526001600160a01b0360408a205416918282141580612869575b6128455761258085614863565b6001600160801b0381166001600160801b03831611612815575090899291858452600b60205260408420926125fd6001600160a01b03855416946002809101546001600160801b036001600160801b03196125df87608094851c61488e565b938c8b52600b60205260408b2001938454931b169116178155613a68565b6001600160801b03612621816020840151169282604081835116920151169061368a565b1611156127e4575b868552600b6020526001600160a01b036001604087200154166126566001600160801b03841685836147d7565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806127da575b612770575b833314159081612765575b8161275a575b506126e8575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016124b3565b823b156104ca57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612742575b80806126b1565b61274b906135ab565b61275657863861273b565b8680fd5b9050831415386126ab565b843b151591506126a5565b803b1561054e57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af16127c6575b505061269a565b6127cf906135ab565b61054e5784386127bf565b50803b1515612695565b868552600b6020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612629565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506128738561476e565b15612573565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106675760203660031901126106675760ff6001604060043593848152600b60205220015460a81c16156106db576108b6602091614a57565b50346106675760203660031901126106675760043590818152600b60205260ff600160408320015460a81c1615612213578061293e83613d80565b926005841015611c175760026020940361295f575b50506040519015158152f35b8152600b8352604090205460f01c60ff1690503880612953565b503461066757806003193601126106675760206001600160a01b03600a5416604051908152f35b503461066757602080600319360112610b0957600435906129bf613f4c565b818352600b815260ff600160408520015460a81c161561221357818352600b815260ff600160408520015460a01c1615612b4a576129fc8261476e565b156121c85781600052600581526001600160a01b038060406000205416600b835260ff60016040600020015460b01c16159081612b40575b5080612b38575b612b20577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526005835260406000205416918215928315612ae5575b846000526005825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612acd575080f35b60249060405190637e27328960e01b82526004820152fd5b612b0685600052600760205260406000206001600160a01b03198154169055565b806000526006825260406000206000198154019055612a7b565b60248360405190630da9b01360e01b82526004820152fd5b506000612a3b565b9050151538612a34565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461066757612b8a366134cc565b60405191602083019383851067ffffffffffffffff861117611c2b5761112894604052858452613abd565b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db57600160408360ff9360209552600b855220015460a01c166040519015158152f35b503461066757602090816003193601126106675760043590612c26613f4c565b818152600b9283815260ff600160408420015460a81c1615612e7a5782825283815260408220600181015460a01c60ff1615612c745760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611f7957612c9f81600052600b6020526001600160a01b0360406000205416331490565b15611f5957612cad81613c6e565b93818452808352612cc360026040862001613a68565b916001600160801b03938484511685881610156121e75781865282815260ff604087205460f01c16156121b057612d07878683611dc68a9b838a9c9b9c511661368a565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612e60575b01988716988981546001600160801b0319161790556001600160a01b038096168097600585528760408b205416978893865260408b20600101541693612d938c84876147d7565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612e0f578480f35b823b1561054e576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612e51575b81818080808480f35b612e5a906135ab565b81612e48565b60018101600160a01b60ff60a01b19825416179055612d4c565b6024836040519062b8e7e760e51b82526004820152fd5b5034610667576020366003190112610667576001600160801b0360406020926001600160a01b03612ec061348c565b16815260028452205416604051908152f35b5034610667576003199060203683018113610b09576004359167ffffffffffffffff93848411610b095761014090843603011261066757612f11613f4c565b60405193612f1e8561358e565b612f2a846004016134b8565b8552612f38602485016134b8565b6020860152612f4960448501613652565b6040860152612f5a606485016134b8565b6060860152612f6b60848501613581565b6080860152612f7c60a48501613581565b60a0860152612f8d60c48501613902565b60c086015260e4840135908111610b095783019136602384011215610b09576004830135612fba81613914565b93612fc86040519586613614565b8185526024602086019260061b820101933685116106675750602401905b8382106130085760206118658861185a898960e0840152610104369101613962565b82604091613016368561392c565b815201910190612fe6565b503461066757806003193601126106675760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346106675761112861306e366134cc565b916136b9565b50346106675780600319360112610667576020600954604051908152f35b503461066757602036600319011261066757600435808252600b60205260ff600160408420015460a81c16156106db576130cb90613d80565b9060058210156115c357602082158381156130ec575b506040519015158152f35b6001915014826130e1565b50346106675760203660031901126106675760043590818152600b60205260ff600160408320015460a81c161561221357602091604082828152600b85522060ff815460f01c1680613185575b61315c575b50506001600160801b0360405191168152f35b61317e92506001600160801b0360026131789201541691613c6e565b9061368a565b3880613149565b5060ff600182015460a01c1615613144565b5034610667576040366003190112610667576131b161348c565b6024356131bd81613c2a565b3315158061327d575b80613253575b6132235781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600760205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260086020526040842033855260205260ff604085205416156131cc565b50336001600160a01b03821614156131c6565b503461066757602036600319011261066757602061241d600435613666565b503461066757806003193601126106675760405190806003549160018360011c9260018516948515613369575b60209586861081146114db578588528794939291879082156114b957505060011461330f57505061144b92500383613614565b90859250600382527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b85831061335157505061144b9350820101388061143d565b80548389018501528794508693909201918101613339565b93607f16936132dc565b905034610b09576020366003190112610b09576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104c657602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561341a575b81156133f0575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386133e9565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506133e2565b60005b8381106134575750506000910152565b8181015183820152602001613447565b9060209161348081518092818552858086019101613444565b601f01601f1916010190565b600435906001600160a01b038216820361066257565b602435906001600160a01b038216820361066257565b35906001600160a01b038216820361066257565b6060906003190112610662576001600160a01b0390600435828116810361066257916024359081168103610662579060443590565b9181601f840112156106625782359167ffffffffffffffff8311610662576020808501948460051b01011161066257565b90815180825260208080930193019160005b828110613552575050505090565b835180516001600160801b0316865282015164ffffffffff168583015260409094019392810192600101613544565b3590811515820361066257565b610120810190811067ffffffffffffffff821117611c2b57604052565b67ffffffffffffffff8111611c2b57604052565b610160810190811067ffffffffffffffff821117611c2b57604052565b6040810190811067ffffffffffffffff821117611c2b57604052565b6060810190811067ffffffffffffffff821117611c2b57604052565b90601f8019910116810190811067ffffffffffffffff821117611c2b57604052565b67ffffffffffffffff8111611c2b57601f01601f191660200190565b35906001600160801b038216820361066257565b61366f81613c2a565b5060005260076020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116136a357565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156138ea5760009184835260209160058352604092828486205416600b825260ff6001868820015460b01c161590816138e0575b50806138d8575b6138c1578685526005815282848620541694873315159384613811575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876137d9575b808352600684528683206001815401905581835260058452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036137ab5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6137fa82600052600760205260406000206001600160a01b03198154169055565b878352600684528683208054600019019055613747565b91929380915090613880575b1561382b579087839261371e565b848887613848576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156138a5575b8061381d575087825260078352338486842054161461381d565b5085825260088352848220338352835260ff858320541661388b565b602487855190630da9b01360e01b82526004820152fd5b506001613701565b90501515386136fa565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361066257565b67ffffffffffffffff8111611c2b5760051b60200190565b919082604091031261066257604051613944816135dc565b602061395d81839561395581613652565b855201613902565b910152565b91908260409103126106625760405161397a816135dc565b6020808294613988816134b8565b84520135910152565b91908110156139a15760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b03811681036106625790565b9081546139d781613914565b926040936139e86040519182613614565b82815280946020809201926000526020600020906000935b858510613a0f57505050505050565b60018481928451613a1f816135dc565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613a00565b60405190613a56826135f8565b60006040838281528260208201520152565b90604051613a75816135f8565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b03811681036106625790565b3580151581036106625790565b9190613aca8282856136b9565b803b613ad7575b50505050565b613b336001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613467565b03906020816000938185885af190829082613bc9575b5050613b805782613b58614833565b8051919082613b795760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613bb1575038808080613ad1565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613c22575b81613be660209383613614565b81010312610b095751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106675750903880613b49565b3d9150613bd9565b8060005260056020526001600160a01b0360406000205416908115612acd575090565b8051156139a15760200190565b80518210156139a15760209160051b010190565b64ffffffffff80421691600090808252602091600c602052613c92604082206139cb565b9185856020613ca086613c4d565b5101511611613d77578152600b602052604081208585825460c81c161115613d6157506001600160801b039485613cd684613c4d565b5151169583519260019360011015613d4d5750949392919084602060408501510151169581866001985b161115613d11575050505050505090565b909181879881613d258798999a8598613c5a565b5151160116970191868087613d3a8689613c5a565b5101511697829392919796959498613d00565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b80600052600b602052604060002060ff600182015460a01c16600014613da7575050600490565b805460f81c613e00575460a01c64ffffffffff164210613dfa57613dca81613c6e565b90600052600b6020526001600160801b038060026040600020015416911610600014613df557600190565b600290565b50600090565b5050600390565b916000828152602090600582526001600160a01b03604095818784205416600b855260ff6001898620015460b01c16159081613f42575b5080613f37575b613f20579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600586527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613ee8575b169283613ed2575b84875260058852808720846001600160a01b0319825416179055519580a4948152a1565b8387526006885280872060018154019055613eae565b613f0986600052600760205260406000206001600160a01b03198154169055565b838852600689528488208054600019019055613ea6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613e45565b9050151538613e3e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613f7e57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b906001600160a01b036001541660206001600160a01b036060850151166024604051809481937fdcf844a700000000000000000000000000000000000000000000000000000000835260048301525afa80156147625760009061472e575b61402a91506001600160801b036040850151169060206101008601510151916148a9565b6001600160801b0381511660e084015164ffffffffff60c086015116821561470457815180156146da577f000000000000000000000000000000000000000000000000000000000000000081116146a9575064ffffffffff602061408d84613c4d565b510151168110156146525750600090819082815184905b8082106145c1575050505064ffffffffff421664ffffffffff82168110156145815750506001600160801b031680820361454a5750506009549283600052600b6020526040600020916001600160801b0381511660028401906001600160801b03198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206142378951996000198b0190613c5a565b51015160c81b169560f01b16911617171717845560005b8181106144a5575050600185016009556001600160a01b0360608301511660005260026020526001600160801b0380604060002054168160208401511601166001600160a01b036060840151166000526040600020906001600160801b03198254161790556001600160a01b0360208301511680156138ea576142d9866001600160a01b0392613e07565b166144745761430e6001600160a01b036060840151166001600160801b038084511681602086015116011690309033906149e8565b6001600160801b0360408201511680614444575b507fd1aaaf57e122e7b428e079232d56f44a4f2877a9dcb386ea1a442f758dd6e34f6144016001600160a01b03845116926001600160a01b03602086015116946001600160a01b036060820151169661443961441960808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6143ad8c6135dc565b818160a01c168c5260c81c1660208b01520151511695604051998a99610160948b523360208c015260408b0190604090816001600160801b0391828151168552826020820151166020860152015116910152565b60a089015260c08801528060e0880152860190613532565b926101008501906020908164ffffffffff91828151168552015116910152565b6101408301520390a4565b61446e906001600160a01b036060850151166001600160a01b0361010086015151169033906149e8565b38614322565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600c6020526040600020906144c28160e0870151613c5a565b51825468010000000000000000811015611c2b57600181018085558110156139a157600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b169216171790550161424e565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936145e5906001600160801b036145dc8588613c5a565b5151169061488e565b9364ffffffffff8060206145f98685613c5a565b51015116941680851115614615575060018493019092916140a4565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061466384613c4d565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b506020813d60201161475a575b8161474860209383613614565b810103126106625761402a9051614006565b3d915061473b565b6040513d6000823e3d90fd5b60009080825260056020526001600160a01b0380604084205416928333149384156147b3575b505082156147a157505090565b9091506147ae3392613666565b161490565b60ff9294509060409181526008602052818120338252602052205416913880614794565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526148319161482c606483613614565b614ad2565b565b3d1561485e573d9061484482613636565b916148526040519384613614565b82523d6000602084013e565b606090565b61488b9061487081614a57565b90600052600b60205260026040600020015460801c9061368a565b90565b9190916001600160801b03808094169116019182116136a357565b9092916148b4613a49565b936001600160801b03928381169182156149c05767016345785d8a00008082116149895780851161495257506148fe856148ef819386614b6e565b16946020890195865284614b6e565b16918461491560408901948086528287511661488e565b16101561493c5761492e8491826149379551169061368a565b9151169061368a565b168252565b634e487b7160e01b600052600160045260246000fd5b84604491604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b60449250604051917f47152d6700000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050505090506040516149d3816135f8565b60008152600060208201526000604082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611c2b5761483192604052614ad2565b80600052600b602052614a706002604060002001613a68565b81600052600b602052604060002060ff600182015460a01c16600014614aa357506001600160801b039150602001511690565b5460f81c614ab5575061488b90613c6e565b61488b91506001600160801b03604081835116920151169061368a565b6001600160a01b031690614afd600080836020829551910182875af1614af6614833565b9084614c1d565b908151918215159283614b46575b505050614b155750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610b095760200151908115918215036106675750388080614b0b565b90919060001983820983820291828083109203918083039214614c0c57670de0b6b3a76400009081831015614bd557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614c5c5750805115614c3257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614ca7575b614c6d575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15614c6556fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004d983881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614996908162000402823960805181613da3015260a051818181612e810152613e430152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146131df57508063027b6744146131bc57806306fdde03146130f7578063081812fc146130d8578063095ea7b314612fdf5780631400ecec14612f3f5780631c1cdd4c14612eda5780631e99d56914612ebc57806323b872dd14612ea45780632fe4304114612e6957806332fbe22b14612d1157806340e58ee514612a73578063425d30dd14612a2257806342842e0e146129e857806342966c681461280d57806344267570146127e65780634857501f146127705780634869e12d146127355780634cc55e11146122b95780636352211e146122895780636d0cee751461228957806370a082311461221957806375829def146121865780637cad6cd11461208c5780637de6b1db14611e655780637f5799f914611e0a5780638659c27014611ab0578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a61330e565b91604435926001600160801b038085169182860361063f5761029a613d99565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f89614546565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614571565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138b5565b90808483015116918180825116916040015116610395916134f6565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886146d6565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b61049890613417565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b61052090613417565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8896144ad565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f61330e565b9161074981614546565b92610752613d99565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f89614546565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d6132f8565b604061082761330e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614546565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b5034610644576020366003190112610644576004356000602060405161096781613464565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a783613464565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613a77565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a656040519282849384528301906132d3565b0390f35b909192503d8082843e610a7c8184613480565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134a2565b93610ac06040519586613480565b838552858484010111610644575090610ade918480850191016132b0565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b1361330e565b610b1b613d99565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b6286614546565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c54565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613d99565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a614546565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c614571565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138b5565b90610cec818a84015116928260408183511692015116906134f6565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d338186886146d6565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df990613417565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d90613417565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a6144ad565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b6132f8565b61108361330e565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134a2565b936110c06040519586613480565b8585523660248783010111610ae657856110eb9660246020930183880137850101526044359161390a565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613bcd565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d6132f8565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b505061131192500383613480565b610a656040519282849384528301906132d3565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613bcd565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613d99565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a75760249061152886613780565b956115366040519788613480565b8652878601920101913683116104a757905b86838310611743575050505081519061156082613780565b9261156e6040519485613480565b828452601f1961157d84613780565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613a9a565b51511683808b6115b785613a9a565b51015116880116604051916115cb83613464565b82528a8201526115da88613a9a565b526115e487613a9a565b5060019260015b8381106116b6575050505050611603856004016138e9565b91611610602487016138e9565b9161161d60448801613823565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d016138fd565b948161166360a48c016138fd565b976040519d8e6133fa565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016137ce565b610100820152613df5565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613aa7565b51511696600019890190613aa7565b51015116916116ea868a613aa7565b510151160116604051916116fd83613464565b82528d82015261170d828c613aa7565b52611718818b613aa7565b50016115eb565b60405161172b81613464565b60008152600083820152828289010152018790611581565b6040916117503685613798565b815201910190611548565b503461064457602036600319011261064457606061014060405161177e8161342b565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201526040516117bd81613448565b84815284602082015284604082015261012082015201526004358152600960205260ff600160408320015460a81c1615611a985760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a82576118ae9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138b5565b6101208301526118bf600435613bcd565b6005811015611a6e5761014092600261198b9214611a63575b6101208101516001600160a01b0360a08301511664ffffffffff60408401511694606084015115159061010085015115159260c086015115159160e08701511515936001600160a01b03885116996080604064ffffffffff60208c015116946004358152600a602052209901511515926040519b6119558d61342b565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152613837565b82820152610a65604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261012081015160406001600160801b039182815116858801528260208201511661016088015201511661018085015201516101a0808401526101c083019061339e565b8260608201526118d8565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611ae390369060040161336d565b9190611aed613d99565b83925b808410611afb578480f35b611b068482846137fd565b3593611b10613d99565b848652600980855260ff90600190828260408b20015460a81c1615611df357878952808752604089208281015460a01c841615611b5f5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611ddb57611b908160005260096020526001600160a01b0360406000205416331490565b15611dbb57611b9e81613abb565b818a52828952611bb3600260408c20016138b5565b906001600160801b0395868351168783161015611da357838c52848b5260408c205460f01c1615611d8b5791818a611c0485898f9a999896611bfa8c9983879351166134f6565b95015116906134f6565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611d72575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cb78b85886146d6565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d1b575b505050505050600101929190611af0565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d5e575b80808080611d0a565b611d6790613417565b61052b578438611d55565b818601600160a01b60ff60a01b19825416179055611c69565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e5192610a659452600a60205220613837565b60405191829160208352602083019061339e565b503461064457602080600319360112610ae65760043590611e84613d99565b8183526009815260ff600160408520015460a81c161561207557611ea782613bcd565b60058110156120615760048103611ed05760248360405190634a5541ef60e01b82526004820152fd5b60038103611ef0576024836040519063fe19f19f60e01b82526004820152fd5b60021461204957611f178260005260096020526001600160a01b0360406000205416331490565b1561202a578183526009815260ff604084205460f01c161561201257818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611fba575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611ffe575b80611f8b565b61200790613417565b6104a3578238611ff8565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a3578183541633810361215d575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121495760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121a06132f8565b9080546001600160a01b03808216933385036121f2576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361223b6132f8565b168015612258578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122a8600435613a77565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576122ec90369060040161336d565b90916024359081116104a75761230690369060040161336d565b61230e613d99565b8083036126fe57845b838110612322578580f35b61232d8185876137fd565b359061233a8186886137fd565b35875260036020526001600160a01b0360408820541661236361235e8386886137fd565b613823565b9061236c613d99565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b038216156126e65783895260036020526001600160a01b0360408a2054169182821415806126d6575b6126b2576123e485614546565b6001600160801b0381166001600160801b038316116126825750908992918584526009602052604084209261246a6001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961244c87608094851c614571565b938c8b52600960205260408b2001938454931b1691161781556138b5565b6001600160801b0361248e81602084015116928260408183511692015116906134f6565b161115612651575b86855260096020526001600160a01b036001604087200154166124c36001600160801b03841685836146d6565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612647575b6125dd575b8333141590816125d2575b816125c7575b50612555575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612317565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125af575b808061251e565b6125b890613417565b6125c35786386125a8565b8680fd5b905083141538612518565b843b15159150612512565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612633575b5050612507565b61263c90613417565b61052b57843861262c565b50803b1515612502565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612496565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506126e0856144ad565b156123d7565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614730565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c161561207557806127ab83613bcd565b926005841015611a6e576002602094036127cc575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127c0565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae6576004359061282c613d99565b8183526009815260ff600160408520015460a81c1615612075578183526009815260ff600160408520015460a01c16156129b757612869826144ad565b1561202a5781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129ad575b50806129a5575b61298d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612952575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161293a575080f35b60249060405190637e27328960e01b82526004820152fd5b61297385600052600560205260406000206001600160a01b03198154169055565b8060005260048252604060002060001981540190556128e8565b60248360405190630da9b01360e01b82526004820152fd5b5060006128a8565b90501515386128a1565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610644576129f736613338565b60405191602083019383851067ffffffffffffffff861117611a82576110eb9460405285845261390a565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612a93613d99565b81815260099283815260ff600160408420015460a81c1615612cfa5782825283815260408220600181015460a01c60ff1615612ae15760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611ddb57612b0c8160005260096020526001600160a01b0360406000205416331490565b15611dbb57612b1a81613abb565b93818452808352612b30600260408620016138b5565b916001600160801b03938484511685881610156120495781865282815260ff604087205460f01c161561201257612b7e878683612b748a9b838a9c9b9c51166134f6565b97015116906134f6565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612ce0575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c138c84876146d6565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612c8f578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612cd1575b81818080808480f35b612cda90613417565b81612cc8565b60018101600160a01b60ff60a01b19825416179055612bc3565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d50613d99565b60405193612d5d856133fa565b612d6984600401613324565b8552612d7760248501613324565b6020860152612d88604485016134be565b604086015260648401356001600160a01b03811681036104a3576060860152612db3608485016133ed565b6080860152612dc460a485016133ed565b60a0860152612dd560c4850161376e565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e0281613780565b93612e106040519586613480565b8185526024602086019260061b820101933685116106445750602401905b838210612e505760206116ae886116a3898960e08401526101043691016137ce565b82604091612e5e3685613798565b815201910190612e2e565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eb636613338565b91613525565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f1390613bcd565b9060058210156114895760208215838115612f34575b506040519015158152f35b600191501482612f29565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c161561207557602091604082828152600985522060ff815460f01c1680612fcd575b612fa4575b50506001600160801b0360405191168152f35b612fc692506001600160801b036002612fc09201541691613abb565b906134f6565b3880612f91565b5060ff600182015460a01c1615612f8c565b503461064457604036600319011261064457612ff96132f8565b60243561300581613a77565b331515806130c5575b8061309b575b61306b5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615613014565b50336001600160a01b038216141561300e565b50346106445760203660031901126106445760206122a86004356134d2565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131b2575b60209586861081146113a15785885287949392918790821561137f57505060011461315857505061131192500383613480565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061319a57505061131193508201013880611303565b80548389018501528794508693909201918101613182565b93607f1693613125565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613286575b811561325c575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613255565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061324e565b60005b8381106132c35750506000910152565b81810151838201526020016132b3565b906020916132ec815180928185528580860191016132b0565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133be575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133b0565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611a8257604052565b67ffffffffffffffff8111611a8257604052565b610160810190811067ffffffffffffffff821117611a8257604052565b6060810190811067ffffffffffffffff821117611a8257604052565b6040810190811067ffffffffffffffff821117611a8257604052565b90601f8019910116810190811067ffffffffffffffff821117611a8257604052565b67ffffffffffffffff8111611a8257601f01601f191660200190565b35906001600160801b038216820361063f57565b6134db81613a77565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161350f57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561375657600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161374c575b5080613744575b61372d57868552600381528284862054169487331515938461367d575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613645575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136175750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61366682600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135b3565b919293809150906136ec575b15613697579087839261358a565b8488876136b4576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613711575b806136895750878252600583523384868420541614613689565b5085825260068352848220338352835260ff85832054166136f7565b602487855190630da9b01360e01b82526004820152fd5b50600161356d565b9050151538613566565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611a825760051b60200190565b919082604091031261063f576040516137b081613464565b60206137c98183956137c1816134be565b85520161376e565b910152565b919082604091031261063f576040516137e681613464565b60208082946137f481613324565b84520135910152565b919081101561380d5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461384381613780565b926040936138546040519182613480565b82815280946020809201926000526020600020906000935b85851061387b57505050505050565b6001848192845161388b81613464565b64ffffffffff87546001600160801b038116835260801c168382015281520193019401939161386c565b906040516138c281613448565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b9190613917828285613525565b803b613924575b50505050565b6139806001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906132d3565b03906020816000938185885af190829082613a16575b50506139cd57826139a5614516565b80519190826139c65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036139fe57503880808061391e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613a6f575b81613a3360209383613480565b81010312610ae65751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106445750903880613996565b3d9150613a26565b8060005260036020526001600160a01b036040600020541690811561293a575090565b80511561380d5760200190565b805182101561380d5760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613adf60408220613837565b9185856020613aed86613a9a565b5101511611613bc45781526009602052604081208585825460c81c161115613bae57506001600160801b039485613b2384613a9a565b5151169583519260019360011015613b9a5750949392919084602060408501510151169581866001985b161115613b5e575050505050505090565b909181879881613b728798999a8598613aa7565b5151160116970191868087613b878689613aa7565b5101511697829392919796959498613b4d565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613bf4575050600490565b805460f81c613c4d575460a01c64ffffffffff164210613c4757613c1781613abb565b9060005260096020526001600160801b038060026040600020015416911610600014613c4257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613d8f575b5080613d84575b613d6d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d35575b169283613d1f575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613cfb565b613d5686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613cf3565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c92565b9050151538613c8b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dcb57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e176001600160801b03604084015116602061010085015101519061458c565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144835781518015614459577f00000000000000000000000000000000000000000000000000000000000000008111614428575064ffffffffff6020613e7a84613a9a565b510151168110156143d15750600090819082815184905b808210614340575050505064ffffffffff421664ffffffffff82168110156143005750506001600160801b03168082036142c9575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061402d8951996000198b0190613aa7565b51015160c81b169560f01b16911617171717845560005b818110614224575050600185016007556001600160a01b0360208301511680156137565761407a866001600160a01b0392613c54565b166141f3576140a56001600160a01b036060840151166001600160801b038351169030903390614665565b6001600160801b03602082015116806141c3575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141b861419960808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141428c613464565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061339e565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b6141ed906001600160a01b036060850151166001600160a01b036101008601515116903390614665565b386140b9565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142418160e0870151613aa7565b51825468010000000000000000811015611a82576001810180855581101561380d57600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614044565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614364906001600160801b0361435b8588613aa7565b51511690614571565b9364ffffffffff8060206143788685613aa7565b5101511694168085111561439457506001849301909291613e91565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff60206143e284613a9a565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156144f2575b505082156144e057505090565b9091506144ed33926134d2565b161490565b60ff92945090604091815260066020528181203382526020522054169138806144d3565b3d15614541573d90614527826134a2565b916145356040519384613480565b82523d6000602084013e565b606090565b61456e9061455381614730565b90600052600960205260026040600020015460801c906134f6565b90565b9190916001600160801b038080941691160191821161350f57565b9190916040519061459c82613464565b600091828152826020820152936001600160801b03928383169182156146465767016345785d8a000080821161460f57506145d8859184614847565b16602087019281845211156145fb575090826145f6925116906134f6565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061465a82613464565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a82576146d4926040526147ab565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146d49161472b606483613480565b6147ab565b80600052600960205261474960026040600020016138b5565b816000526009602052604060002060ff600182015460a01c1660001461477c57506001600160801b039150602001511690565b5460f81c61478e575061456e90613abb565b61456e91506001600160801b0360408183511692015116906134f6565b6001600160a01b0316906147d6600080836020829551910182875af16147cf614516565b90846148f6565b90815191821515928361481f575b5050506147ee5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae657602001519081159182150361064457503880806147e4565b909190600019838209838202918280831092039180830392146148e557670de0b6b3a764000090818310156148ae57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614935575080511561490b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614980575b614946575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561493e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615f2090816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661570a565b91601e604660ff61030b8460146050848d60081c1606011661570a565b981606011661570a565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615091565b16906151fa565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff8091169116615545565b610120516101805190929161059d602161053a6064610533818706615a17565b950461570a565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615b23565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b60008152866159eb565b156147c9576090945b6106fa8661570a565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b6109ec82615e9d565b808211156147c15750945b610a0287870161570a565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615e1f565b610d1b82615e9d565b808211156147b95750935b610d326028860161570a565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615190565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615aea565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615aea565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615aea565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615aea565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615190565b92611ce9611ce3614d0b565b896159eb565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615d63565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615d63565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615dcb565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615dcb565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461570a565b9461570a565b9761570a565b9161570a565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561570a565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561570a565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b610160516141049061585b565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e081905261585b565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b906159eb565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d84876159da565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa92831561508657600093615063575b50815192614eb6846149de565b60118452614eeb6020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159eb565b15614f295750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614f1f836149de565b600d835282015290565b614f668351614f37816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159eb565b15614fa45750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614f9a836149de565b600e835282015290565b614fe18351614fb2816149de565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159eb565b1561501f5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191615015836149de565b600f835282015290565b61505f9083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61507f91933d8091833e61507781836149fa565b810190614bce565b9138614ea9565b82513d6000823e3d90fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150c9816149de565b6000928392839251915afa6150dc614b9e565b9080615113575b1561510f5760208180518101031261510b57602001519060ff82168203615108575090565b80fd5b5080fd5b5090565b5060208151146150e3565b6040519061512b826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615164826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151f89294936040519586926020946151b281518092888089019101614909565b84016151c682518093888085019101614909565b016151d982518093878085019101614909565b016151ec82518093868085019101614909565b010380855201836149fa565b565b801561550a57600091806154e5575090505b600190808281101561527657505050615223615157565b614c2d602260405183615240829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c6800011156154885760409081519060a0820182811067ffffffffffffffff821117614402578084526152ad8161498a565b6000815282528251906152bf826149de565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152f9816149de565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615330816149de565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615368816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545c575b508451946153af866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615449575050505061542a615430917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615425866149de565b61570a565b91615a17565b916005851015614b6c57614c2d9460051b015192615190565b81810184015188820185015283016153e0565b9591926103e89081851061547f57508680916064600a870406950493019661539d565b939296506153a2565b505061549261511e565b614c2d6028604051836154af829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a9182156154f657500461520c565b80634e487b7160e01b602492526012600452fd5b5050604051615518816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155ad575061555a615157565b614c2d602660405183615577829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f811161567c576001810361563957614c2d60206156016040516155d2816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570a565b60405193816156198693518092868087019101614909565b820161562d82518093868085019101614909565b010380845201826149fa565b614c2d602061560160405161564d816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570a565b5061568561511e565b614c2d602a604051836156a2829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b906156e282614b82565b6156ef60405191826149fa565b8281528092615700601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561584d575b506d04ee2d6d415b85acef81000000008083101561583e575b50662386f26fc100008083101561582f575b506305f5e10080831015615820575b5061271080831015615811575b506064821015615801575b600a809210156157f7575b6001908160216157a2600187016156d8565b95860101905b6157b4575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f2579190826157a8565b6157ad565b9160010191615790565b9190606460029104910191615785565b6004919392049101913861577a565b6008919392049101913861576d565b6010919392049101913861575e565b6020919392049101913861574c565b604093508104915038615733565b8051156159c65760405161586e816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159b05760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159b05761590d906002959492951b6156d8565b936020850193839284518501935b84811061595d57505050505060039051068060011461594a5760021461593f575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061591b565b634e487b7160e01b600052601160045260246000fd5b506040516159d38161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615a01575050505090565b60209293945082012092012014388080806157ad565b80615a2957506040516159d38161498a565b600a811015615a8e57615a3b9061570a565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7e8151809260208686019101614909565b81010360028101845201826149fa565b615a979061570a565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ada8151809260208686019101614909565b81010360018101845201826149fa565b60405190615af7826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d5557615b31615aea565b906127109081039081116159b057614c2d91615b4f6101369261570a565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bdb815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c6382518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cc482518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159d38161498a565b60306151f8919392936040519481615d85879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dbc8251809360208785019101614909565b010360108101855201836149fa565b60256151f8919392936040519481615ded879351809260208087019101614909565b820164010714051160dd1b6020820152615e108251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e9557906000916000915b818310615e4457505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e7787856159da565b511614615e8d575b600d01936001019190615e32565b849350615e7f565b505050600090565b60009080518015615e9557906000916000915b818310615ec25750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ef587856159da565b511614615f0b575b601001936001019190615eb0565b849350615efd56fea164736f6c6343000817000a"; From c62bf9f75aed0ecf3ffa01468b84a80a2418f1ec Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 11 Mar 2024 17:24:16 +0000 Subject: [PATCH 058/132] Move precompiles to precompiles directory (#841) * refactor: move precompiles to precompiles directory * chore: ignore precompiles directory in codecov --- codecov.yml | 1 + package.json | 1 + {test/utils => precompiles}/Precompiles.sol | 11 ++++++----- shell/update-precompiles.sh | 2 +- test/utils/Precompiles.t.sol | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) rename {test/utils => precompiles}/Precompiles.sol (99%) diff --git a/codecov.yml b/codecov.yml index eca34cf1b..1ab56482e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -5,6 +5,7 @@ coverage: status: patch: off ignore: + - "precompiles" - "script" - "src/libraries/NFTSVG.sol" - "src/libraries/SVGElements.sol" diff --git a/package.json b/package.json index 758035e0c..458f92b70 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ }, "files": [ "artifacts", + "precompiles", "src", "test/utils", "CHANGELOG.md", diff --git a/test/utils/Precompiles.sol b/precompiles/Precompiles.sol similarity index 99% rename from test/utils/Precompiles.sol rename to precompiles/Precompiles.sol index 9997d9932..c0a70d315 100644 --- a/test/utils/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -2,11 +2,11 @@ // solhint-disable max-line-length,no-inline-assembly,reason-string pragma solidity >=0.8.22; -import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2NFTDescriptor } from "../../src/SablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../src/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; /// @notice This is useful for external integrations seeking to test against the exact deployed bytecode, as recompiling /// with via IR enabled would be time-consuming. @@ -187,6 +187,7 @@ contract Precompiles { /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} /// 4. {SablierV2LockupTranched} + /// 5. {SablierV2NFTDescriptor} function deployCore(address initialAdmin) public returns ( diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index 9a69e33fb..008db274a 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -17,7 +17,7 @@ lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinea lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) nft_descriptor=$(cat out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) -precompiles_path="test/utils/Precompiles.sol" +precompiles_path="precompiles/Precompiles.sol" if [ ! -f $precompiles_path ]; then echo "Precompiles file does not exist" exit 1 diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 6fdbac31d..f9a0073ad 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -3,13 +3,13 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; +import { Precompiles } from "../../precompiles/Precompiles.sol"; import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; -import { Precompiles } from "./Precompiles.sol"; contract Precompiles_Test is Base_Test { using LibString for address; From cbe1c0d61d74217d6ad01599318d5551f3381b2b Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:23:05 +0200 Subject: [PATCH 059/132] Remove duplicated script (#845) * refactor: remove duplicated scripts build: use other script in deploy-multi-chain docs: remove duplicated contract name in deployCore natspec * docs: re-order contracts in natspec --- precompiles/Precompiles.sol | 1 - script/DeployCore3.s.sol | 34 ------------------------ script/DeployDeterministicCore3.s.sol | 37 --------------------------- shell/deploy-multi-chain.sh | 4 +-- 4 files changed, 2 insertions(+), 74 deletions(-) delete mode 100644 script/DeployCore3.s.sol delete mode 100644 script/DeployDeterministicCore3.s.sol diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index c0a70d315..3aea2bc37 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -187,7 +187,6 @@ contract Precompiles { /// 2. {SablierV2LockupDynamic} /// 3. {SablierV2LockupLinear} /// 4. {SablierV2LockupTranched} - /// 5. {SablierV2NFTDescriptor} function deployCore(address initialAdmin) public returns ( diff --git a/script/DeployCore3.s.sol b/script/DeployCore3.s.sol deleted file mode 100644 index 61a149b59..000000000 --- a/script/DeployCore3.s.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @notice Deploys these contracts in the following order: -/// -/// 1. {SablierV2NFTDescriptor} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} -contract DeployCore3 is BaseScript { - function run(address initialAdmin) - public - virtual - broadcast - returns ( - SablierV2NFTDescriptor nftDescriptor, - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) - { - nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); - } -} diff --git a/script/DeployDeterministicCore3.s.sol b/script/DeployDeterministicCore3.s.sol deleted file mode 100644 index 2ba0a06a5..000000000 --- a/script/DeployDeterministicCore3.s.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @notice Deploys these contracts at deterministic addresses across chains, in the following order: -/// -/// 1. {SablierV2NFTDescriptor} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} -/// -/// @dev Reverts if any contract has already been deployed. -contract DeployDeterministicCore3 is BaseScript { - function run(address initialAdmin) - public - virtual - broadcast - returns ( - SablierV2NFTDescriptor nftDescriptor, - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) - { - bytes32 salt = constructCreate2Salt(); - nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); - } -} diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index bd3e9123b..c02d55c26 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -288,7 +288,7 @@ for chain in "${provided_chains[@]}"; do if [[ ${DETERMINISTIC_DEPLOYMENT} == true ]]; then echo -e "${SC}+${NC} Deterministic address" if [[ ${sol_script} == "" ]]; then - deployment_command+=("script" "script/DeployDeterministicCore3.s.sol" "--ffi") + deployment_command+=("script" "script/DeployDeterministicCore.s.sol" "--ffi") else deployment_command+=("script" "${sol_script}") fi @@ -307,7 +307,7 @@ for chain in "${provided_chains[@]}"; do else # Construct the command if [[ ${sol_script} == "" ]]; then - deployment_command+=("script" "script/DeployCore3.s.sol") + deployment_command+=("script" "script/DeployCore.s.sol") else deployment_command+=("script" "${sol_script}") fi From 6217fcfd84f30b330c8fc561ae17811bdf7b80cd Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:20:44 +0200 Subject: [PATCH 060/132] refactor: rename functions in Helpers (#848) chore: correct explantory comments in _calculateStreamedAmount --- src/SablierV2LockupDynamic.sol | 4 ++-- src/SablierV2LockupTranched.sol | 9 ++++----- src/libraries/Helpers.sol | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 21d45b6ae..dc42e60b1 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -150,8 +150,8 @@ contract SablierV2LockupDynamic is noDelegateCall returns (uint256 streamId) { - // Checks: check the durations and generate the canonical segments. - LockupDynamic.Segment[] memory segments = Helpers.checkDurationsAndCalculateTimestamps(params.segments); + // Generate the canonical segments. + LockupDynamic.Segment[] memory segments = Helpers.calculateSegmentsTimestamps(params.segments); // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index fae72f6bb..f42e674d7 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -145,8 +145,8 @@ contract SablierV2LockupTranched is noDelegateCall returns (uint256 streamId) { - // Checks: check the durations and generate the canonical tranches. - LockupTranched.Tranche[] memory tranches = Helpers.checkDurationsAndCalculateTimestamps(params.tranches); + // Generate the canonical tranches. + LockupTranched.Tranche[] memory tranches = Helpers.calculateTranchesTimestamps(params.tranches); // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( @@ -196,12 +196,11 @@ contract SablierV2LockupTranched is } // Sum the amounts in all tranches that precede the current time. + // Using unchecked arithmetic is safe because the sum of the tranche amounts is equal to the total amount + // at this point. uint128 streamedAmount = tranches[0].amount; uint40 currentTrancheTimestamp = tranches[1].timestamp; uint256 index = 1; - - // Using unchecked arithmetic is safe here because the sums of the tranche amounts are equal to the total amount - // at this point. unchecked { while (currentTrancheTimestamp <= currentTime) { streamedAmount += tranches[index].amount; diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 71a8c738f..6e84a9d4d 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -139,8 +139,8 @@ library Helpers { _checkTranches(tranches, depositAmount, startTime); } - /// @dev Checks that the segment array counts match, and then adjusts the segments by calculating the timestamps. - function checkDurationsAndCalculateTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) + /// @dev Calculate the timestamps and return the segments. + function calculateSegmentsTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) internal view returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) @@ -172,8 +172,8 @@ library Helpers { } } - /// @dev Checks that the tranche array counts match, and then adjusts the tranches by calculating the timestamps. - function checkDurationsAndCalculateTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + /// @dev Calculate the timestamps and return the tranches. + function calculateTranchesTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) internal view returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) From ba4d2463ca414bf540077d94980f34bff8168f8e Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 14 Mar 2024 13:57:47 +0200 Subject: [PATCH 061/132] docs: correct requirements in tranched createWithTimestamps --- src/interfaces/ISablierV2LockupTranched.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 457c557cf..2dd6c3f61 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -115,7 +115,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. - /// - `params.tranches` must have at least one tranche, but not more than `MAX_SEGMENT_COUNT`. + /// - `params.tranches` must have at least one tranche, but not more than `MAX_TRANCHE_COUNT`. /// - `params.startTime` must be less than the first tranche's timestamp. /// - The tranche timestamps must be arranged in ascending order. /// - The last tranche timestamp (i.e. the stream's end time) must be in the future. From 64d9bfbe5c9165b3d1931723c735b9a612e679d3 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 14 Mar 2024 14:08:33 +0200 Subject: [PATCH 062/132] refactor: use singular form in function names --- src/SablierV2LockupDynamic.sol | 2 +- src/SablierV2LockupTranched.sol | 2 +- src/libraries/Helpers.sol | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index dc42e60b1..172f72780 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -151,7 +151,7 @@ contract SablierV2LockupDynamic is returns (uint256 streamId) { // Generate the canonical segments. - LockupDynamic.Segment[] memory segments = Helpers.calculateSegmentsTimestamps(params.segments); + LockupDynamic.Segment[] memory segments = Helpers.calculateSegmentTimestamps(params.segments); // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index f42e674d7..bfd35ab77 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -146,7 +146,7 @@ contract SablierV2LockupTranched is returns (uint256 streamId) { // Generate the canonical tranches. - LockupTranched.Tranche[] memory tranches = Helpers.calculateTranchesTimestamps(params.tranches); + LockupTranched.Tranche[] memory tranches = Helpers.calculateTrancheTimestamps(params.tranches); // Checks, Effects and Interactions: create the stream. streamId = _createWithTimestamps( diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index 6e84a9d4d..b3823d3c7 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -140,7 +140,7 @@ library Helpers { } /// @dev Calculate the timestamps and return the segments. - function calculateSegmentsTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) + function calculateSegmentTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) internal view returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) @@ -173,7 +173,7 @@ library Helpers { } /// @dev Calculate the timestamps and return the tranches. - function calculateTranchesTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + function calculateTrancheTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) internal view returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) From efd4a4bd6b34ca043770bb5ac3bbe3c6c139df7b Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Thu, 14 Mar 2024 14:16:57 +0200 Subject: [PATCH 063/132] Feat/include recipient in StreamLD StreamLL StreamLT (#850) * feat: include recipient in StreamLD StreamLL StreamLT * test: include recipient check wherever getStream is used * docs: update dev natspec --------- Co-authored-by: smol-ninja --- precompiles/Precompiles.sol | 6 +++--- src/SablierV2LockupDynamic.sol | 3 ++- src/SablierV2LockupLinear.sol | 1 + src/SablierV2LockupTranched.sol | 1 + src/types/DataTypes.sol | 9 ++++++--- test/fork/LockupDynamic.t.sol | 1 + test/fork/LockupLinear.t.sol | 1 + test/fork/LockupTranched.t.sol | 1 + .../fuzz/lockup-dynamic/createWithDurations.t.sol | 1 + .../fuzz/lockup-dynamic/createWithTimestamps.t.sol | 1 + .../fuzz/lockup-linear/createWithTimestamps.t.sol | 1 + .../fuzz/lockup-tranched/createWithDurations.t.sol | 1 + .../fuzz/lockup-tranched/createWithTimestamps.t.sol | 1 + test/utils/Assertions.sol | 3 +++ test/utils/Defaults.sol | 3 +++ 15 files changed, 27 insertions(+), 7 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 3aea2bc37..76da39f79 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -25,11 +25,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f1962005b303881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260075561572e908162000402823960805181613acb015260a051818181610cdb0152613b8c0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe6080806040526004908136101561001557600080fd5b60003560e01c90816301ffc9a7146127a657508063027b67441461278357806306fdde03146126bb578063081812fc1461269d578063095ea7b3146125965780631400ecec146124f05780631c1cdd4c1461248a5780631e99d5691461246c57806323b872dd1461245557806331df3d481461234957806340e58ee514612048578063425d30dd14611ff257806342842e0e14611fa157806342966c6814611d8f5780634426757014611d685780634857501f14611cee5780634869e12d14611cb15780634cc55e1114611bb657806354c022921461191a5780636352211e146118eb5780636d0cee75146118eb57806370a082311461187b57806375829def146117e15780637cad6cd1146116e35780637de6b1db146114c65780638659c2701461116f578063894e9a0d14610dee5780638f69b99314610d535780639067b67714610cfe5780639188ec8414610cc357806395d89b4114610bb2578063a22cb46514610af4578063a80fc07114610a9d578063ad35efd414610a24578063b2564569146109ce578063b637b8651461096f578063b88d4fde146108e6578063b8a3be66146108b0578063b971302a1461085c578063bc2be1be14610807578063c156a11d146106b1578063c87b56dd1461059d578063cc364f4814610501578063d4dbd20b146104aa578063d511609f14610459578063d975dfed1461040b578063e985e9c5146103b4578063ea5ead1914610386578063eac8f5b81461032f578063f590c176146102ca578063f851a440146102a35763fdd46d601461025d57600080fd5b3461029e57606036600319011261029e576102766128d2565b604435906001600160801b038216820361029e5761029c92610296613ac1565b356134b3565b005b600080fd5b3461029e57600036600319011261029e5760206001600160a01b0360005416604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060406000205460f81c6040519015158152f35b6024916040519162b8e7e760e51b8352820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160a01b0360016040600020015416604051908152f35b503461029e57604036600319011261029e5761029c90356103a56128d2565b6103ae826142bc565b91613108565b3461029e57604036600319011261029e576103cd6128bc565b6103d56128d2565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a576020610448836142bc565b6001600160801b0360405191168152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060026040600020015460801c604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160801b0360036040600020015416604051908152f35b503461029e57602036600319011261029e578035906000602060405161052681612a22565b828152015281600052600960205260ff60016040600020015460a81c161561031a575060005260096020526040806000205464ffffffffff82519161056a83612a22565b818160a01c16835260c81c16602082015261059b825180926020908164ffffffffff91828151168552015116910152565bf35b503461029e5760208060031936011261029e57600082356105bd81613842565b5060446001600160a01b03600854169460405195869384927fe9dc6375000000000000000000000000000000000000000000000000000000008452309084015260248301525afa9182156106a55760009261062c575b50610628604051928284938452830190612897565b0390f35b9091503d806000833e61063f8183612a6f565b810190828183031261029e5780519067ffffffffffffffff821161029e570181601f8201121561029e57805161067481612a91565b926106826040519485612a6f565b81845284828401011161029e5761069e91848085019101612874565b9038610613565b6040513d6000823e3d90fd5b503461029e57604036600319011261029e578035906106ce6128d2565b916106d7613ac1565b80600052600960205260ff60016040600020015460a81c16156107f1578060005260036020526001600160a01b038060406000205416938433036107ce5761071e836142bc565b6001600160801b0381166107bd575b50818116156107a557826107409161397c565b9081168061075f576024848460405191637e27328960e01b8352820152fd5b840361076757005b6107a1916040519485946364283d7b60e01b865285019193929060409160608401956001600160a01b038093168552602085015216910152565b0390fd5b602484600060405191633250574960e11b8352820152fd5b6107c8908685613108565b3861072d565b50506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602492506040519162b8e7e760e51b8352820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602064ffffffffff60406000205460a01c16604051908152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160a01b0360406000205416604051908152f35b503461029e57602036600319011261029e57356000526009602052602060ff60016040600020015460a81c166040519015158152f35b503461029e57608036600319011261029e576109006128bc565b6109086128d2565b906064359267ffffffffffffffff841161029e573660238501121561029e578301359161093483612a91565b926109426040519485612a6f565b808452366024828701011161029e57602081600092602461029c9801838801378501015260443591612f94565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600a6020526106286109ba6040600020612f04565b604051918291602083526020830190612962565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060ff60016040600020015460b01c166040519015158152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a8857610a5e906138f5565b604051906005811015610a7357602092508152f35b602183634e487b7160e01b6000525260246000fd5b60405162b8e7e760e51b815291820152602490fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a5750600052600960205260206001600160801b0360026040600020015416604051908152f35b503461029e57604036600319011261029e57610b0e6128bc565b6024359081151580920361029e576001600160a01b0316918215610b825750336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b60249083604051917f5b08ba18000000000000000000000000000000000000000000000000000000008352820152fd5b503461029e57600036600319011261029e576040519060006002549060018260011c92600181168015610cb9575b6020958686108214610ca457508487528693929186908215610c84575050600114610c27575b50610c1392500383612a6f565b610628604051928284938452830190612897565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c6c575050610c13935082010138610c06565b80548389018501528794508693909201918101610c55565b60ff191685820152610c1395151560051b8501019250389150610c069050565b602290634e487b7160e01b6000525260246000fd5b93607f1693610be0565b3461029e57600036600319011261029e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602064ffffffffff60406000205460c81c16604051908152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a8857610d8d906138f5565b9060058210159081610dcb5760028314918215610de0575b8215610db9575b6020836040519015158152f35b909150610dcb57602091143880610dac565b602190634e487b7160e01b6000525260246000fd5b506003831491506000610da5565b503461029e57602036600319011261029e57604051610160810181811067ffffffffffffffff82111761115a576060916101409160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e08201526000610100820152610e69612eb1565b61012082015201528035600052600960205260ff60016040600020015460a81c16156111425780356000526009602052604060002090610f39600260405193610eb185612a52565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201612ed0565b610120830152610f4981356138f5565b600581101561112d57600214611121575b6101208201516001600160a01b0360a08401511664ffffffffff604085015116606085015115159061010086015115159260c087015115159160e08801511515936001600160a01b03895116918835600052600a602052604060002099608064ffffffffff6020830151169101511515936040519a8b67ffffffffffffffff61016082818101109201111761110c57506101608b016040908152908b5260208b01919091528901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101409161103490612f04565b82820152610628604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261012081015160406001600160801b039182815116858801528260208201511661016088015201511661018085015201516101a0808401526101c0830190612962565b604190634e487b7160e01b6000525260246000fd5b60006060830152610f5a565b602182634e487b7160e01b6000525260246000fd5b6024906040519062b8e7e760e51b8252803590820152fd5b604183634e487b7160e01b6000525260246000fd5b503461029e576020908160031936011261029e57803567ffffffffffffffff811161029e576111a19036908301612931565b90926111ab613ac1565b6000915b8083106111b857005b6111c3838287612e56565b35926111cd613ac1565b8360005260099081845260ff60019080826040600020015460a81c16156114b057866000528386526040600020818382015460a01c16600014611221576024898960405191634a5541ef60e01b8352820152fd5b96909192939495965460f81c611499576112518160005260096020526001600160a01b0360406000205416331490565b156114775761125f8161387d565b94816000528088526112776002604060002001612ed0565b956001600160801b03938488511685831610156114605783600052828a5260406000205460f01c16156114495780848a6112b76112c194838c5116612ae5565b9901511690612ae5565b95826000528189528860406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161783558781169a8b15611430575b600380940198861698896fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9486528160406000205416978896526040600020015416946113798985886146fa565b604080518981526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce788604051848152a1803b6113dc575b50505050600191500191906111af565b803b1561029e578860006084926001988296604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af1611421575b8080806113cc565b61142a90612a3e565b38611419565b898401600160a01b60ff60a01b19825416179055611327565b60248a84604051916339c6dc7360e21b8352820152fd5b60248b85604051916322cad1af60e11b8352820152fd5b6040805163216caf0d60e01b8152808a01928352336020840152918291010390fd5b876024916040519163fe19f19f60e01b8352820152fd5b602488886040519162b8e7e760e51b8352820152fd5b503461029e576020908160031936011261029e5780356114e4613ac1565b806000526009835260ff60016040600020015460a81c16156107f157611509816138f5565b926005841015610a7357838303611531576024838360405191634a5541ef60e01b8352820152fd5b6003840361155057602483836040519163fe19f19f60e01b8352820152fd5b90600284146116cc576115798160005260096020526001600160a01b0360406000205416331490565b156116aa57806000526009825260ff60406000205460f01c1615611693578060005260098252604060002060ff60f01b198154169055604051817f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600383526001600160a01b036040600020541693843b61161f575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78484604051908152a1005b843b1561029e578160248160007ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7988782967f450154640000000000000000000000000000000000000000000000000000000085528401525af1611684575b806115f3565b61168d90612a3e565b8361167e565b82602491604051916339c6dc7360e21b8352820152fd5b6040805163216caf0d60e01b8152938401918252336020830152839250010390fd5b82602491604051916322cad1af60e11b8352820152fd5b503461029e57602036600319011261029e5780356001600160a01b039081811680910361029e5781600054163381036117b5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101919082116117a0577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c604083815190600182526020820152a1005b601190634e487b7160e01b6000525260246000fd5b604080516331b339a960e21b81526001600160a01b039092168286019081523360208201528291010390fd5b503461029e57602036600319011261029e576117fb6128bc565b600054906001600160a01b039081831633810361184f57506001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b604080516331b339a960e21b81526001600160a01b039092168287019081523360208201528291010390fd5b503461029e57602036600319011261029e576001600160a01b0361189d6128bc565b1680156118ba576000526020526020604060002054604051908152f35b6024826000604051917f89c62b64000000000000000000000000000000000000000000000000000000008352820152fd5b503461029e57602036600319011261029e5761190960209135613842565b6001600160a01b0360405191168152f35b503461029e5760209060031990828236011261029e5780359167ffffffffffffffff9081841161029e576101208436039182011261029e5761195a613ac1565b60c4840135906022190181121561029e578301828101359082821161029e57602401606082023603811361029e57611993913691612d87565b92835192816119a185612d6f565b946119af6040519687612a6f565b808652601f196119be82612d6f565b018860005b828110611b985750505064ffffffffff90814216956001600160801b0398896119eb82613b1d565b515116828c6119f984613b1d565b5101511685806040611a0a86613b1d565b510151168b01169060405192611a1f84612a06565b83528d8301526040820152611a338a613b1d565b52611a3d89613b1d565b5060019360015b8c8b8d878410611b0957908c8a611a5c818e01612e90565b92611a6960248301612e90565b92611a7660448401612e7c565b946064840135946001600160a01b039586811680910361029e57611b0198611ac198611af698611aa860848a01612ea4565b9481611ab660a48c01612ea4565b976040519d8e6129d3565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e27565b610100820152613b3e565b604051908152f35b8899509084806040611b468a87611b368c9d9e9f9b9c99988b90611b2d828d613b2a565b5151169a613b2a565b5101511694600019890190613b2a565b51015116816040611b57888c613b2a565b5101511601169160405193611b6b85612a06565b84528301526040820152611b7f828d613b2a565b52611b8a818c613b2a565b500190879594939291611a44565b9091929350611ba5612eb1565b82828a0101520190888593926119c3565b503461029e57604036600319011261029e5767ffffffffffffffff90803582811161029e57611be89036908301612931565b9260243590811161029e57611c009036908401612931565b919092611c0b613ac1565b828503611c7b575060005b848110611c1f57005b80611c75611c306001938886612e56565b35611c3c838987612e56565b3560005260036020526001600160a01b0360406000205416611c67611c6285898b612e56565b612e7c565b91611c70613ac1565b6134b3565b01611c16565b6044908386604051927faec934400000000000000000000000000000000000000000000000000000000084528301526024820152fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57602061044883614754565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57600090611d2c836138f5565b906005821015610dcb5750600203611d4c575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611d3f565b3461029e57600036600319011261029e5760206001600160a01b0360085416604051908152f35b503461029e576020908160031936011261029e57803591611dae613ac1565b826000526009815260ff60016040600020015460a81c1615611f8b57826000526009815260ff60016040600020015460a01c1615611f5b57611def83614223565b15611f375782600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611f2d575b5080611f25575b611f0e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790846000526003835260406000205416918215928315611ed4575b856000526003825260406000206001600160a01b03198154169055856000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4858152a1611ebe57005b60249160405191637e27328960e01b8352820152fd5b611ef586600052600560205260406000206001600160a01b03198154169055565b8060005284825260406000206000198154019055611e6e565b6024838560405191630da9b01360e01b8352820152fd5b506000611e2e565b9050151538611e27565b506040805163216caf0d60e01b815291820192835233602084015290918291010390fd5b50602491604051917f817cd639000000000000000000000000000000000000000000000000000000008352820152fd5b506024916040519162b8e7e760e51b8352820152fd5b503461029e57611fb0366128fc565b90604051926020840184811067ffffffffffffffff821117611fdd5761029c955060405260008452612f94565b604186634e487b7160e01b6000525260246000fd5b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a57506000526009602052602060ff60016040600020015460a01c166040519015158152f35b503461029e576020908160031936011261029e578035612066613ac1565b80600052600980845260ff60016040600020015460a81c16156123335781600052808452604060002060ff600182015460a01c166000146120b8576024848460405191634a5541ef60e01b8352820152fd5b5460f81c61231c576120e08260005260096020526001600160a01b0360406000205416331490565b156122fa576120ee8261387d565b92826000528185526121066002604060002001612ed0565b936001600160801b03908186511682821610156122e3578460005283875260ff60406000205460f01c16156122cc578661219582847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509a61218b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796838d5116612ae5565b9a01511690612ae5565b86600052858252604060002095865498600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b1617885560038684169889156122b2575b0195811695866fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809a169a8b91600386528a61225c8d604060002054169d8e96895260016040600020015416966122328b878a6146fa565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051868152a1843b61226e57005b843b1561029e576000946084938692604051988997889663c6f5ed0f60e01b88528701526024860152604485015260648401525af16122a957005b61029c90612a3e565b60018101600160a01b60ff60a01b198254161790556121db565b60248386604051916339c6dc7360e21b8352820152fd5b60248386604051916322cad1af60e11b8352820152fd5b506040805163216caf0d60e01b81529283019182523360208301528291010390fd5b602483836040519163fe19f19f60e01b8352820152fd5b602483836040519162b8e7e760e51b8352820152fd5b503461029e576003199060203683011261029e5780359167ffffffffffffffff9081841161029e5761014090843603011261029e57612386613ac1565b60405190612393826129d3565b61239e8484016128e8565b82526123ac602485016128e8565b60208301526123bd60448501612aad565b604083015260648401356001600160a01b038116810361029e5760608301526123e8608485016129c6565b60808301526123f960a485016129c6565b60a083015261240a60c48501612d5d565b60c083015260e484013590811161029e578301913660238401121561029e57602093612445611af692611b0195602436928201359101612d87565b60e0840152610104369101612e27565b3461029e5761029c612466366128fc565b91612b14565b3461029e57600036600319011261029e576020600754604051908152f35b503461029e57602036600319011261029e57803580600052600960205260ff60016040600020015460a81c1615610a88576124c4906138f5565b906005821015610dcb57602082158381156124e5575b506040519015158152f35b6001915014826124da565b503461029e57602036600319011261029e5780359081600052600960205260ff60016040600020015460a81c161561031a576020826000908060005260098352604060002060ff815460f01c1680612584575b61255b575b50506001600160801b0360405191168152f35b61257d92506001600160801b036002612577920154169161387d565b90612ae5565b8280612548565b5060ff600182015460a01c1615612543565b503461029e57604036600319011261029e576125b06128bc565b90602435906125be82613842565b903315158061268a575b8061265c575b61262b575081906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b602490604051907fa9fbf51f0000000000000000000000000000000000000000000000000000000082523390820152fd5b506001600160a01b038216600052600660205260406000203360005260205260ff60406000205416156125ce565b50336001600160a01b03831614156125c8565b503461029e57602036600319011261029e5761190960209135612ac1565b503461029e57600036600319011261029e57604051906000600190600154918260011c92600181168015612779575b6020958686108214610ca457508487528693929186908215610c8457505060011461271c5750610c1392500383612a6f565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612761575050610c13935082010138610c06565b8054838901850152879450869390920191810161274a565b93607f16936126ea565b3461029e57600036600319011261029e57602060405167016345785d8a00008152f35b823461029e57602036600319011261029e5735907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029e57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561284a575b8115612820575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612819565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612812565b60005b8381106128875750506000910152565b8181015183820152602001612877565b906020916128b081518092818552858086019101612874565b601f01601f1916010190565b600435906001600160a01b038216820361029e57565b602435906001600160a01b038216820361029e57565b35906001600160a01b038216820361029e57565b606090600319011261029e576001600160a01b0390600435828116810361029e5791602435908116810361029e579060443590565b9181601f8401121561029e5782359167ffffffffffffffff831161029e576020808501948460051b01011161029e57565b90815180825260208080930193019160005b828110612982575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff169086015260609094019392810192600101612974565b3590811515820361029e57565b610120810190811067ffffffffffffffff8211176129f057604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176129f057604052565b6040810190811067ffffffffffffffff8211176129f057604052565b67ffffffffffffffff81116129f057604052565b610140810190811067ffffffffffffffff8211176129f057604052565b90601f8019910116810190811067ffffffffffffffff8211176129f057604052565b67ffffffffffffffff81116129f057601f01601f191660200190565b35906001600160801b038216820361029e57565b612aca81613842565b5060005260056020526001600160a01b036040600020541690565b6001600160801b039182169082160391908211612afe57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015612d4557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612d3b575b5080612d33575b612d1c578685526003815282848620541694873315159384612c6c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612c34575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612c065750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612c5582600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612ba2565b91929380915090612cdb575b15612c865790878392612b79565b848887612ca3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612d00575b80612c785750878252600583523384868420541614612c78565b5085825260068352848220338352835260ff8583205416612ce6565b602487855190630da9b01360e01b82526004820152fd5b506001612b5c565b9050151538612b55565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361029e57565b67ffffffffffffffff81116129f05760051b60200190565b929192612d9382612d6f565b604094612da36040519283612a6f565b8195848352602080930191606080960285019481861161029e57925b858410612dcf5750505050505050565b868483031261029e57825190612de482612a06565b612ded85612aad565b8252858501359067ffffffffffffffff8216820361029e57828792838b950152612e18868801612d5d565b86820152815201930192612dbf565b919082604091031261029e57604051612e3f81612a22565b6020808294612e4d816128e8565b84520135910152565b9190811015612e665760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029e5790565b356001600160a01b038116810361029e5790565b35801515810361029e5790565b60405190612ebe82612a06565b60006040838281528260208201520152565b90604051612edd81612a06565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612f1081612d6f565b92604093612f216040519182612a6f565b82815280946020809201926000526020600020906000935b858510612f4857505050505050565b60018481928451612f5881612a06565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612f39565b9190612fa1828285612b14565b803b612fae575b50505050565b61300a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612897565b03906020816000938185885af1908290826130a0575b5050613057578261302f61428c565b80519190826130505760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613088575038808080612fa8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613100575b816130bd60209383612a6f565b810103126130fc5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036130f95750903880613020565b80fd5b5080fd5b3d91506130b0565b92919092613114613ac1565b60009381855260099260209380855260409260ff6001858a20015460a81c161561349d5784885281865260ff6001858a20015460a01c16613486576001600160a01b0391828216928315613476576001600160801b039384861691821561345f57888c5260038a5280888d20541693848314158061344f575b61342c5761319a8a6142bc565b87811685116133fb57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906131cb916142e4565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561320090612ed0565b90808683015116918184818351169201511661321b91612ae5565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966133ce575b8782528552200154169461325e8189886146fa565b8a51908152a480331415806133c4575b61335f575b823314159081613354575b81613349575b506132b8575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613345578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613336575b85948161328a565b61333f90612a3e565b3861332e565b8780fd5b905082141538613284565b833b1515915061327e565b803b156133c0578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16133b1575b50613273565b6133ba90612a3e565b386133ab565b8880fd5b50803b151561326e565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613249565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506134598a614223565b1561318d565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c161561349d578785815281875260ff6001868320015460a01c1661382b576001600160a01b039081851692831561381b576001600160801b03938486169182156138045789845260038b528489852054169485831415806137f4575b6137d1576135588b838e61354483614754565b9289525260028c8820015460801c90612ae5565b87811685116137a05750908b8b928387528282528b808820998b838c54169b6002015460801c90613588916142e4565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556135bd90612ed0565b818086830151169381835116920151166135d691612ae5565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613772575b848852825260018c88200154169461361a818c886146fa565b8b51908152a48133141580613768575b613702575b508133141590816136f7575b816136ec575b50613674575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156136e8578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16136d0575b808061328a565b6136da8691612a3e565b6136e457846136c9565b8480fd5b8280fd5b905081141538613641565b823b1515915061363b565b813b156130f9578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613754575b5061362f565b61376091929a50612a3e565b97388061374e565b50813b151561362a565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613601565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506137fe8b614223565b15613531565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115613865575090565b60249060405190637e27328960e01b82526004820152fd5b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156138eb5760c81c1611156138d95750600a6020526001604060002054116000146138d0576138cd906143d0565b90565b6138cd906142ff565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c1660001461391c575050600490565b805460f81c613975575460a01c64ffffffffff16421061396f5761393f8161387d565b9060005260096020526001600160801b03806002604060002001541691161060001461396a57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613ab7575b5080613aac575b613a95579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613a5d575b169283613a47575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613a23565b613a7e86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613a1b565b602486885190630da9b01360e01b82526004820152fd5b5081811615156139ba565b90501515386139b3565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613af357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612e665760200190565b8051821015612e665760209160051b010190565b90613b606001600160801b0360408401511660206101008501510151906145b0565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141f957815180156141cf577f0000000000000000000000000000000000000000000000000000000000000000811161419e575064ffffffffff6040613bc384613b1d565b510151168110156141475750600090819082815184905b8082106140b6575050505064ffffffffff421664ffffffffff82168110156140765750506001600160801b031680820361403f575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613d768951996000198b0190613b2a565b51015160c81b169560f01b16911617171717845560005b818110613f6d575050600185016007556001600160a01b036020830151168015612d4557613dc3866001600160a01b039261397c565b16613f3c57613dee6001600160a01b036060840151166001600160801b038351169030903390614689565b6001600160801b0360208201511680613f0c575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613f01613ee260808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613e8b8c612a22565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612962565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613f36906001600160a01b036060850151166001600160a01b036101008601515116903390614689565b38613e02565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613f8a8160e0870151613b2a565b518254680100000000000000008110156129f05760018101808555811015612e6657600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613d8d565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936140da906001600160801b036140d18588613b2a565b515116906142e4565b9364ffffffffff8060406140ee8685613b2a565b5101511694168085111561410a57506001849301909291613bda565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061415884613b1d565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614268575b5050821561425657505090565b9091506142633392612ac1565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614249565b3d156142b7573d9061429d82612a91565b916142ab6040519384612a6f565b82523d6000602084013e565b606090565b6138cd906142c981614754565b90600052600960205260026040600020015460801c90612ae5565b9190916001600160801b0380809416911601918211612afe57565b64ffffffffff614334600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166147cf565b91808252600a602052604082208054156143bc5790829167ffffffffffffffff935261438e602083205482845260096020526143896001600160801b03968760026040882001541696879360801c16906148bf565b61492d565b9283136143a45750506143a090614a17565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff80421660008381526009602052604091828220908351916143f683612a52565b80549661012061447c60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612ed0565b94019384528452600a602052614493858520612f04565b91849680876144a186613b1d565b5101511692828288955b161061457a57509161452f6143899284888161453498976001600160801b039e8f6144d6898c613b2a565b5151169d8e9a67ffffffffffffffff60206144f18c84613b2a565b510151169984836145028385613b2a565b510151169650801561456e5761451e9293506000190190613b2a565b5101511680925b03169203166147cf565b6148bf565b92831361454d5750506145478391614a17565b16011690565b5160200151929392831692841683101591506145699050575090565b905090565b50505051168092614525565b8093986001600160801b0390816145918c89613b2a565b51511601169801928282808a6145a7888a613b2a565b510151166144ab565b919091604051906145c082612a22565b600091828152826020820152936001600160801b039283831691821561466a5767016345785d8a000080821161463357506145fc8591846155df565b166020870192818452111561461f5750908261461a92511690612ae5565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061467e82612a22565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176129f0576146f892604052614a53565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146f89161474f606483612a6f565b614a53565b80600052600960205261476d6002604060002001612ed0565b816000526009602052604060002060ff600182015460a01c166000146147a057506001600160801b039150602001511690565b5460f81c6147b257506138cd9061387d565b6138cd91506001600160801b036040818351169201511690612ae5565b600160ff1b8082149081156148b5575b5061488b57600081121561488257614808816000035b600084121561487b578360000390614aef565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614844576000199118131561483e5790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614aef565b614808816147f5565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386147df565b806148da57506148d557670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146149275750806148ff575050670de0b6b3a764000090565b670de0b6b3a764000081146149235761491e906143896138cd93614be9565b614d2b565b5090565b91505090565b600160ff1b808214908115614a0d575b506149e35760008112156149da57614966816000035b60008412156149d35783600003906155df565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161499c576000199118131561483e5790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906155df565b61496681614953565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b905082143861493d565b60008112614a225790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614a7e600080836020829551910182875af1614a7761428c565b908461568e565b908151918215159283614ac7575b505050614a965750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b8192935090602091810103126130fc5760200151908115918215036130f95750388080614a8c565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614bab5782851015614b6f57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614bb9570490565b634e487b7160e01b600052601260045260246000fd5b8015614bb9576ec097ce7bc90715b34b9f10000000000590565b80600080831315614cfa57670de0b6b3a764000092838112614cd757506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ccb57506706f05b59d3b20000905b848213614c9f5750505050500290565b808391020590671bc16d674ec80000821215614cbe575b831d90614c8f565b8091950194831d90614cb6565b93505093925050020290565b6000199392508015614bb9576ec097ce7bc90715b34b9f10000000000591614c0a565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614d5a5768033dd1780914b9711419811261396f57614d5190600003614d2b565b6138cd90614bcf565b680a688906bd8affffff81136155ae57670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615491575b66ff0000000000008316615389575b65ff00000000008316615289575b64ff000000008316615191575b63ff00000083166150a1575b62ff00008316614fb9575b61ff008316614ed9575b60ff8316614e02575b02911c60bf031c90565b60808316614ec7575b838316614eb5575b60208316614ea3575b60108316614e91575b60088316614e7f575b60048316614e6d575b60028316614e5b575b6001831615614df8576801000000000000000102831c614df8565b6801000000000000000102831c614e40565b6801000000000000000302831c614e37565b6801000000000000000602831c614e2e565b6801000000000000000b02831c614e25565b6801000000000000001602831c614e1c565b6801000000000000002c02831c614e13565b6801000000000000005902831c614e0b565b6180008316614fa7575b6140008316614f95575b6120008316614f83575b6110008316614f71575b6108008316614f5f575b6104008316614f4d575b6102008316614f3b575b610100831615614def57680100000000000000b102831c614def565b6801000000000000016302831c614f1f565b680100000000000002c602831c614f15565b6801000000000000058c02831c614f0b565b68010000000000000b1702831c614f01565b6801000000000000162e02831c614ef7565b68010000000000002c5d02831c614eed565b680100000000000058b902831c614ee3565b62800000831661508f575b62400000831661507d575b62200000831661506b575b621000008316615059575b620800008316615047575b620400008316615035575b620200008316615023575b62010000831615614de5576801000000000000b17202831c614de5565b680100000000000162e402831c615006565b6801000000000002c5c802831c614ffb565b68010000000000058b9102831c614ff0565b680100000000000b172102831c614fe5565b68010000000000162e4302831c614fda565b680100000000002c5c8602831c614fcf565b6801000000000058b90c02831c614fc4565b6380000000831661517f575b6340000000831661516d575b6320000000831661515b575b63100000008316615149575b63080000008316615137575b63040000008316615125575b63020000008316615113575b6301000000831615614dda5768010000000000b1721802831c614dda565b6801000000000162e43002831c6150f5565b68010000000002c5c86002831c6150e9565b680100000000058b90c002831c6150dd565b6801000000000b17217f02831c6150d1565b680100000000162e42ff02831c6150c5565b6801000000002c5c85fe02831c6150b9565b68010000000058b90bfc02831c6150ad565b6480000000008316615277575b6440000000008316615265575b6420000000008316615253575b6410000000008316615241575b640800000000831661522f575b640400000000831661521d575b640200000000831661520b575b640100000000831615614dce57680100000000b17217f802831c614dce565b68010000000162e42ff102831c6151ec565b680100000002c5c85fe302831c6151df565b6801000000058b90bfce02831c6151d2565b68010000000b17217fbb02831c6151c5565b6801000000162e42fff002831c6151b8565b68010000002c5c8601cc02831c6151ab565b680100000058b90c0b4902831c61519e565b658000000000008316615377575b654000000000008316615365575b652000000000008316615353575b651000000000008316615341575b65080000000000831661532f575b65040000000000831661531d575b65020000000000831661530b575b65010000000000831615614dc1576801000000b17218355102831c614dc1565b680100000162e430e5a202831c6152eb565b6801000002c5c863b73f02831c6152dd565b68010000058b90cf1e6e02831c6152cf565b680100000b1721bcfc9a02831c6152c1565b68010000162e43f4f83102831c6152b3565b680100002c5c89d5ec6d02831c6152a5565b6801000058b91b5bc9ae02831c615297565b6680000000000000831661547f575b6640000000000000831661546d575b6620000000000000831661545b575b66100000000000008316615449575b66080000000000008316615437575b66040000000000008316615425575b66020000000000008316615413575b6601000000000000831615614db35768010000b17255775c0402831c614db3565b6801000162e525ee054702831c6153f2565b68010002c5cc37da949202831c6153e3565b680100058ba01fb9f96d02831c6153d4565b6801000b175effdc76ba02831c6153c5565b680100162f3904051fa102831c6153b6565b6801002c605e2e8cec5002831c6153a7565b68010058c86da1c09ea202831c615398565b678000000000000000831661558f575b674000000000000000831661557d575b672000000000000000831661556b575b6710000000000000008316615559575b6708000000000000008316615547575b6704000000000000008316615535575b6702000000000000008316615523575b670100000000000000831615614da457680100b1afa5abcbed6102831c614da4565b68010163da9fb33356d802831c615501565b680102c9a3e778060ee702831c6154f1565b6801059b0d31585743ae02831c6154e1565b68010b5586cf9890f62a02831c6154d1565b6801172b83c7d517adce02831c6154c1565b6801306fe0a31b7152df02831c6154b1565b5077b504f333f9de6484800000000000000000000000000000006154a1565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461567d57670de0b6b3a7640000908183101561564657947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906156cd57508051156156a357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615718575b6156de575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156156d656fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962005a0b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156099081620004028239608051816139a6015260a051818181610c9f0152613a670152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab82614197565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614197565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614197565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a6145d5565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161462f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d83826140fe565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d85886145d5565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614167565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a614197565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be916141bf565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b878252855220015416946131518189886145d5565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a6140fe565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e6134378361462f565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b916141bf565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c886145d5565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b6140fe565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a8906142ab565b90565b6137a8906141da565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b03604084015116602061010085015101519061448b565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140d457815180156140aa577f00000000000000000000000000000000000000000000000000000000000000008111614079575064ffffffffff6040613a9e846139f8565b510151168110156140225750600090819082815184905b808210613f91575050505064ffffffffff421664ffffffffff8216811015613f515750506001600160801b0316808203613f1a575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c518951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e48575050600185016007556001600160a01b03602083015116801561078d57613c9e866001600160a01b0392613857565b16613e1757613cc96001600160a01b036060840151166001600160801b038351169030903390614564565b6001600160801b0360208201511680613de7575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613ddc613dbd60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d668c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e11906001600160a01b036060850151166001600160a01b036101008601515116903390614564565b38613cdd565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e658160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c68565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fb5906001600160801b03613fac8588613a05565b515116906141bf565b9364ffffffffff806040613fc98685613a05565b51015116941680851115613fe557506001849301909291613ab5565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614033846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614143575b5050821561413157505090565b90915061413e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614124565b3d15614192573d90614178826129b2565b916141866040519384612990565b82523d6000602084013e565b606090565b6137a8906141a48161462f565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff61420f600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146aa565b91808252600a602052604082208054156142975790829167ffffffffffffffff9352614269602083205482845260096020526142646001600160801b03968760026040882001541696879360801c169061479a565b614808565b92831361427f57505061427b906148f2565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff80421660008381526009602052604091828220908351916142d183612973565b80549661012061435760026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a60205261436e858520612df7565b918496808761437c866139f8565b5101511692828288955b161061445557509161440a6142649284888161440f98976001600160801b039e8f6143b1898c613a05565b5151169d8e9a67ffffffffffffffff60206143cc8c84613a05565b510151169984836143dd8385613a05565b5101511696508015614449576143f99293506000190190613a05565b5101511680925b03169203166146aa565b61479a565b92831361442857505061442283916148f2565b16011690565b5160200151929392831692841683101591506144449050575090565b905090565b50505051168092614400565b8093986001600160801b03908161446c8c89613a05565b51511601169801928282808a614482888a613a05565b51015116614386565b9190916040519061449b82612943565b600091828152826020820152936001600160801b03928383169182156145455767016345785d8a000080821161450e57506144d78591846154ba565b16602087019281845211156144fa575090826144f592511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061455982612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb576145d39260405261492e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526145d39161462a606483612990565b61492e565b8060005260096020526146486002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c1660001461467b57506001600160801b039150602001511690565b5460f81c61468d57506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b600160ff1b808214908115614790575b5061476657600081121561475d576146e3816000035b60008412156147565783600003906149ca565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f57600019911813156147195790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149ca565b6146e3816146d0565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ba565b806147b557506147b057670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146148025750806147da575050670de0b6b3a764000090565b670de0b6b3a764000081146147fe576147f9906142646137a893614ac4565b614c06565b5090565b91505090565b600160ff1b8082149081156148e8575b506148be5760008112156148b557614841816000035b60008412156148ae5783600003906154ba565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161487757600019911813156147195790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ba565b6148418161482e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614818565b600081126148fd5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614959600080836020829551910182875af1614952614167565b9084615569565b9081519182151592836149a2575b5050506149715750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614967565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a865782851015614a4a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a94570490565b634e487b7160e01b600052601260045260246000fd5b8015614a94576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bd557670de0b6b3a764000092838112614bb257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ba657506706f05b59d3b20000905b848213614b7a5750505050500290565b808391020590671bc16d674ec80000821215614b99575b831d90614b6a565b8091950194831d90614b91565b93505093925050020290565b6000199392508015614a94576ec097ce7bc90715b34b9f10000000000591614ae5565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c355768033dd1780914b9711419811261384a57614c2c90600003614c06565b6137a890614aaa565b680a688906bd8affffff811361548957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661536c575b66ff0000000000008316615264575b65ff00000000008316615164575b64ff00000000831661506c575b63ff0000008316614f7c575b62ff00008316614e94575b61ff008316614db4575b60ff8316614cdd575b02911c60bf031c90565b60808316614da2575b838316614d90575b60208316614d7e575b60108316614d6c575b60088316614d5a575b60048316614d48575b60028316614d36575b6001831615614cd3576801000000000000000102831c614cd3565b6801000000000000000102831c614d1b565b6801000000000000000302831c614d12565b6801000000000000000602831c614d09565b6801000000000000000b02831c614d00565b6801000000000000001602831c614cf7565b6801000000000000002c02831c614cee565b6801000000000000005902831c614ce6565b6180008316614e82575b6140008316614e70575b6120008316614e5e575b6110008316614e4c575b6108008316614e3a575b6104008316614e28575b6102008316614e16575b610100831615614cca57680100000000000000b102831c614cca565b6801000000000000016302831c614dfa565b680100000000000002c602831c614df0565b6801000000000000058c02831c614de6565b68010000000000000b1702831c614ddc565b6801000000000000162e02831c614dd2565b68010000000000002c5d02831c614dc8565b680100000000000058b902831c614dbe565b628000008316614f6a575b624000008316614f58575b622000008316614f46575b621000008316614f34575b620800008316614f22575b620400008316614f10575b620200008316614efe575b62010000831615614cc0576801000000000000b17202831c614cc0565b680100000000000162e402831c614ee1565b6801000000000002c5c802831c614ed6565b68010000000000058b9102831c614ecb565b680100000000000b172102831c614ec0565b68010000000000162e4302831c614eb5565b680100000000002c5c8602831c614eaa565b6801000000000058b90c02831c614e9f565b6380000000831661505a575b63400000008316615048575b63200000008316615036575b63100000008316615024575b63080000008316615012575b63040000008316615000575b63020000008316614fee575b6301000000831615614cb55768010000000000b1721802831c614cb5565b6801000000000162e43002831c614fd0565b68010000000002c5c86002831c614fc4565b680100000000058b90c002831c614fb8565b6801000000000b17217f02831c614fac565b680100000000162e42ff02831c614fa0565b6801000000002c5c85fe02831c614f94565b68010000000058b90bfc02831c614f88565b6480000000008316615152575b6440000000008316615140575b642000000000831661512e575b641000000000831661511c575b640800000000831661510a575b64040000000083166150f8575b64020000000083166150e6575b640100000000831615614ca957680100000000b17217f802831c614ca9565b68010000000162e42ff102831c6150c7565b680100000002c5c85fe302831c6150ba565b6801000000058b90bfce02831c6150ad565b68010000000b17217fbb02831c6150a0565b6801000000162e42fff002831c615093565b68010000002c5c8601cc02831c615086565b680100000058b90c0b4902831c615079565b658000000000008316615252575b654000000000008316615240575b65200000000000831661522e575b65100000000000831661521c575b65080000000000831661520a575b6504000000000083166151f8575b6502000000000083166151e6575b65010000000000831615614c9c576801000000b17218355102831c614c9c565b680100000162e430e5a202831c6151c6565b6801000002c5c863b73f02831c6151b8565b68010000058b90cf1e6e02831c6151aa565b680100000b1721bcfc9a02831c61519c565b68010000162e43f4f83102831c61518e565b680100002c5c89d5ec6d02831c615180565b6801000058b91b5bc9ae02831c615172565b6680000000000000831661535a575b66400000000000008316615348575b66200000000000008316615336575b66100000000000008316615324575b66080000000000008316615312575b66040000000000008316615300575b660200000000000083166152ee575b6601000000000000831615614c8e5768010000b17255775c0402831c614c8e565b6801000162e525ee054702831c6152cd565b68010002c5cc37da949202831c6152be565b680100058ba01fb9f96d02831c6152af565b6801000b175effdc76ba02831c6152a0565b680100162f3904051fa102831c615291565b6801002c605e2e8cec5002831c615282565b68010058c86da1c09ea202831c615273565b678000000000000000831661546a575b6740000000000000008316615458575b6720000000000000008316615446575b6710000000000000008316615434575b6708000000000000008316615422575b6704000000000000008316615410575b67020000000000000083166153fe575b670100000000000000831615614c7f57680100b1afa5abcbed6102831c614c7f565b68010163da9fb33356d802831c6153dc565b680102c9a3e778060ee702831c6153cc565b6801059b0d31585743ae02831c6153bc565b68010b5586cf9890f62a02831c6153ac565b6801172b83c7d517adce02831c61539c565b6801306fe0a31b7152df02831c61538c565b5077b504f333f9de64848000000000000000000000000000000061537c565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461555857670de0b6b3a7640000908183101561552157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155a8575080511561557e57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155f3575b6155b9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155b156fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f6200496b3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360075561458e9081620003dd8239608051816139100152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f2757508063027b674414612f0457806306fdde0314612e3f578063081812fc14612e20578063095ea7b314612d275780631400ecec14612c875780631c1cdd4c14612c225780631e99d56914612c0457806323b872dd14612bec57806340e58ee51461296e578063425d30dd1461291d57806342842e0e146128cd57806342966c68146126f257806344267570146126cb5780634857501f146126555780634869e12d1461261a5780634cc55e111461218a57806353b157271461206b5780636352211e1461203b5780636d0cee751461203b57806370a0823114611fcb57806375829def14611f38578063780a82c814611eeb5780637cad6cd114611df15780637de6b1db14611bca5780638659c27014611879578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613056565b916102786131b3565b92610281613906565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614079565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134aa565b906103b1818684015116928260408183511692015116906131ed565b161115610532575b848c528252600160408c20015416946103d3818a886140a4565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b610491906130d2565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b610519906130d2565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613962565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613056565b9161027881614079565b503461064c57604036600319011261064c5761076b613040565b6040610775613056565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614079565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b061348b565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613103565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a8161365f565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061301b565b0390f35b909192503d8082843e6109fd8184613175565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a3383613197565b93610a416040519586613175565b83855285848401011161064c575090610a5f91848085019101612ff8565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613056565b610a9c613906565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae386614079565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137c1565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613906565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a614079565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a84015116928260408183511692015116906131ed565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140a4565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c906130d2565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e00906130d2565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613962565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613040565b61101a613056565b906064359067ffffffffffffffff82116104a057366023830112156104a0578160040135928461104985613197565b936110576040519586613175565b8585523660248783010111610a675785611082966024602093018388013785010152604435916134f2565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061373a565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613906565b61115b61348b565b9064ffffffffff804216808452816111716134de565b16156112805781806111816134de565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b5760405197611211896130e6565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613159565b61010435918216820361127b57826112739260209452610124358482015260e08201526139cb565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613040565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f792500383613175565b6109e660405192828493845283019061301b565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e9061373a565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101406040516115b38161311f565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201526115ef61348b565b61012082015201526004358152600960205260ff600160408320015460a81c1615611861576004358152600960205260408120906116bd6002604051936116358561313c565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134aa565b6101208301526116ce60043561373a565b600581101561184d576101406101a093600264ffffffffff9314611842575b6101208101518360406001600160a01b0360a085015116966004358152600a6020522054169084604084015116606084015115159661010085015115159160c086015115159060e08701511515926001600160a01b038851169a60808b60208b015116990151151590604051996117638b61311f565b8d8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152610100840152610120830152828201526040519384528260208201511660208501526040810151151560408501526060810151151560608501526001600160a01b0360808201511660808501528260a08201511660a085015260c0810151151560c085015260e0810151151560e0850152610100810151151561010085015261012081015160406001600160801b0391828151166101208801528260208201511685880152015116610160850152015116610180820152f35b8360608201526116ed565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118ac9036906004016130a1565b91906118b6613906565b83925b8084106118c4578480f35b6118cf848284613465565b35936118d9613906565b848652600980855260ff90600190828260408b20015460a81c1615611bb357878952808752604089208281015460a01c8416156119285760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611b9b576119598160005260096020526001600160a01b0360406000205416331490565b15611b7b5761196781613682565b818a5282895261197c600260408c20016134aa565b906001600160801b0395868351168783161015611b6357838c52848b5260408c205460f01c1615611b4b5791818a6119cd85898f9a9998966119c38c9983879351166131ed565b95015116906131ed565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b32575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611a778b85886140a4565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611adb575b5050505050506001019291906118b9565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b1e575b80808080611aca565b611b27906130d2565b610524578438611b15565b818601600160a01b60ff60a01b19825416179055611a32565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611be9613906565b8183526009815260ff600160408520015460a81c1615611dda57611c0c8261373a565b6005811015611dc65760048103611c355760248360405190634a5541ef60e01b82526004820152fd5b60038103611c55576024836040519063fe19f19f60e01b82526004820152fd5b600214611dae57611c7c8260005260096020526001600160a01b0360406000205416331490565b15611d8f578183526009815260ff604084205460f01c1615611d7757818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d1f575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d63575b80611cf0565b611d6c906130d2565b61049c578238611d5d565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ec2575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611eae5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f52613040565b9080546001600160a01b0380821693338503611fa4576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03611fed613040565b16801561200a578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061205a60043561365f565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c57612086613906565b60405190612093826130e6565b61209b613040565b82526120a5613056565b60208301526120b26131b3565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c575060405161210c81613103565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161216283613159565b61012435918216820361127b57826112739260209452610144358482015260e08201526139cb565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121bd9036906004016130a1565b90916024359081116104a0576121d79036906004016130a1565b6121df613906565b8083036125e357845b8381106121f3578580f35b6121fe818587613465565b359061220b818688613465565b35875260036020526001600160a01b0360408820541661222c828587613465565b35906001600160801b038216820361127b57612246613906565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125cb5783895260036020526001600160a01b0360408a2054169182821415806125bb575b612597576122be85614079565b6001600160801b0381166001600160801b038316116125675750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b038111610561579061234f8c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361237381602084015116928260408183511692015116906131ed565b161115612536575b86855260096020526001600160a01b036001604087200154166123a86001600160801b03841685836140a4565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061252c575b6124c2575b8333141590816124b7575b816124ac575b5061243a575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a1016121e8565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612494575b8080612403565b61249d906130d2565b6124a857863861248d565b8680fd5b9050831415386123fd565b843b151591506123f7565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612518575b50506123ec565b612521906130d2565b610524578438612511565b50803b15156123e7565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561237b565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125c585613962565b156122b1565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614100565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611dda57806126908361373a565b92600584101561184d576002602094036126b1575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126a5565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612711613906565b8183526009815260ff600160408520015460a81c1615611dda578183526009815260ff600160408520015460a01c161561289c5761274e82613962565b15611d8f5781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081612892575b508061288a575b612872577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612837575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161281f575080f35b60249060405190637e27328960e01b82526004820152fd5b61285885600052600560205260406000206001600160a01b03198154169055565b8060005260048252604060002060001981540190556127cd565b60248360405190630da9b01360e01b82526004820152fd5b50600061278d565b9050151538612786565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c576128dc3661306c565b60405191602083019383851067ffffffffffffffff86111761290757611082946040528584526134f2565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c576004359061298e613906565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff16156129dc5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611b9b57612a078160005260096020526001600160a01b0360406000205416331490565b15611b7b57612a1581613682565b93818452808352612a2b600260408620016134aa565b916001600160801b0393848451168588161015611dae5781865282815260ff604087205460f01c1615611d7757612a79878683612a6f8a9b838a9c9b9c51166131ed565b97015116906131ed565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612bd2575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b058c84876140a4565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612b81578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bc3575b81818080808480f35b612bcc906130d2565b81612bba565b60018101600160a01b60ff60a01b19825416179055612abe565b503461064c57611082612bfe3661306c565b9161321c565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c5b9061373a565b90600582101561156f5760208215838115612c7c575b506040519015158152f35b600191501482612c71565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611dda57602091604082828152600985522060ff815460f01c1680612d15575b612cec575b50506001600160801b0360405191168152f35b612d0e92506001600160801b036002612d089201541691613682565b906131ed565b3880612cd9565b5060ff600182015460a01c1615612cd4565b503461064c57604036600319011261064c57612d41613040565b602435612d4d8161365f565b33151580612e0d575b80612de3575b612db35781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d5c565b50336001600160a01b0382161415612d56565b503461064c57602036600319011261064c57602061205a6004356131c9565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612efa575b602095868610811461148757858852879493929187908215611465575050600114612ea05750506113f792500383613175565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612ee25750506113f7935082010138806113e9565b80548389018501528794508693909201918101612eca565b93607f1693612e6d565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115612fce575b8115612fa4575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612f9d565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612f96565b60005b83811061300b5750506000910152565b8181015183820152602001612ffb565b9060209161303481518092818552858086019101612ff8565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161290757604052565b610100810190811067ffffffffffffffff82111761290757604052565b6060810190811067ffffffffffffffff82111761290757604052565b610160810190811067ffffffffffffffff82111761290757604052565b610140810190811067ffffffffffffffff82111761290757604052565b6040810190811067ffffffffffffffff82111761290757604052565b90601f8019910116810190811067ffffffffffffffff82111761290757604052565b67ffffffffffffffff811161290757601f01601f191660200190565b604435906001600160801b038216820361127b57565b6131d28161365f565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161320657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561344d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613443575b508061343b575b613424578685526003815282848620541694873315159384613374575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761333c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361330e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61335d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132aa565b919293809150906133e3575b1561338e5790878392613281565b8488876133ab576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613408575b806133805750878252600583523384868420541614613380565b5085825260068352848220338352835260ff85832054166133ee565b602487855190630da9b01360e01b82526004820152fd5b506001613264565b905015153861325d565b6024604051633250574960e11b815260006004820152fd5b91908110156134755760051b0190565b634e487b7160e01b600052603260045260246000fd5b6040519061349882613103565b60006040838281528260208201520152565b906040516134b781613103565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b91906134ff82828561321c565b803b61350c575b50505050565b6135686001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061301b565b03906020816000938185885af1908290826135fe575b50506135b5578261358d614049565b80519190826135ae5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036135e6575038808080613506565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613657575b8161361b60209383613175565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c575090388061357e565b3d915061360e565b8060005260036020526001600160a01b036040600020541690811561281f575090565b600090808252600a60205264ffffffffff918260408220541642106137345760096020526040812092835490808260c81c16918242101561371e576136d39394955060a01c168091039042036142c3565b9082815260096020526001600160801b03926136f98460026040852001541680946143a3565b9283116137065750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613761575050600490565b805460f81c6137ba575460a01c64ffffffffff1642106137b45761378481613682565b9060005260096020526001600160801b0380600260406000200154169116106000146137af57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c161590816138fc575b50806138f1575b6138da579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138a2575b16928361388c575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613868565b6138c386600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613860565b602486885190630da9b01360e01b82526004820152fd5b5081811615156137ff565b90501515386137f8565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361393857565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139a7575b5050821561399557505090565b9091506139a233926131c9565b161490565b60ff9294509060409181526006602052818120338252602052205416913880613988565b906139ec6001600160801b03604084015116602060e085015101519061417b565b916001600160801b0383511660c0820151901561401f5764ffffffffff81511615613ff55764ffffffffff81511690604081019164ffffffffff8351169081811015613fb5575050602081019064ffffffffff8251169081151580613fa3575b613f6257505064ffffffffff90511664ffffffffff8251169081811015613f2257505064ffffffffff8042169151169081811015613ee2575050600754926001600160801b0381511660405190613aa282613103565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b048861313c565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613cfc84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613ec4575b50600184016007556001600160a01b03602083015116801561344d57613d4c856001600160a01b03926137c1565b16613e9357613d776001600160a01b036060840151166001600160801b038351169030903390614254565b6001600160801b0360208201511680613e64575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e5b6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613e8d906001600160a01b036060850151166001600160a01b0360e08601515116903390614254565b38613d8b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d1e565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a4c565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614074573d9061405a82613197565b916140686040519384613175565b82523d6000602084013e565b606090565b6140a19061408681614100565b90600052600960205260026040600020015460801c906131ed565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526140fe916140f9606483613175565b614452565b565b80600052600960205261411960026040600020016134aa565b816000526009602052604060002060ff600182015460a01c1660001461414c57506001600160801b039150602001511690565b5460f81c61415e57506140a190613682565b6140a191506001600160801b0360408183511692015116906131ed565b9190916040519061418b82613159565b600091828152826020820152936001600160801b03928383169182156142355767016345785d8a00008082116141fe57506141c78591846143a3565b16602087019281845211156141ea575090826141e5925116906131ed565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061424982613159565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612907576140fe92604052614452565b670de0b6b3a764000091600019838309928083029283808610950394808603951461437f578285101561434357908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b50508092501561438d570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461444157670de0b6b3a7640000908183101561440a57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b03169061447d600080836020829551910182875af1614476614049565b90846144ee565b9081519182151592836144c6575b5050506144955750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c575038808061448b565b9061452d575080511561450357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614578575b61453e575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561453656fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f620049a33881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c69081620003dd8239608051816139480152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5f57508063027b674414612f3c57806306fdde0314612e77578063081812fc14612e58578063095ea7b314612d5f5780631400ecec14612cbf5780631c1cdd4c14612c5a5780631e99d56914612c3c57806323b872dd14612c2457806340e58ee5146129a6578063425d30dd1461295557806342842e0e1461290557806342966c681461272a57806344267570146127035780634857501f1461268d5780634869e12d146126525780634cc55e11146121c257806353b15727146120a35780636352211e146120735780636d0cee751461207357806370a082311461200357806375829def14611f70578063780a82c814611f235780637cad6cd114611e295780637de6b1db14611c025780638659c270146118b1578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f61308e565b916102786131eb565b9261028161393e565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140b1565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134e2565b906103b181868401511692826040818351169201511690613225565b161115610532575b848c528252600160408c20015416946103d3818a886140dc565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b6104919061310a565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b6105199061310a565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d58961399a565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576004359061074761308e565b91610278816140b1565b503461064c57604036600319011261064c5761076b613078565b604061077561308e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140b1565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134c3565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b8561313b565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613697565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e6604051928284938452830190613053565b0390f35b909192503d8082843e6109fd81846131ad565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131cf565b93610a4160405195866131ad565b83855285848401011161064c575090610a5f91848085019101613030565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a9461308e565b610a9c61393e565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140b1565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f9565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b61393e565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140b1565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613225565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140dc565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c9061310a565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e009061310a565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a61399a565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613078565b61101a61308e565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131cf565b9361105760405195866131ad565b8585523660248783010111610a6757856110829660246020930183880137850101526044359161352a565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f90613772565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c5761115361393e565b61115b6134c3565b9064ffffffffff80421680845281611171613516565b1615611280578180611181613516565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b57604051976112118961311e565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613191565b61010435918216820361127b57826112739260209452610124358482015260e0820152613a03565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613078565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f7925003836131ad565b6109e6604051928284938452830190613053565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e90613772565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101606040516115b381613157565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f66134c3565b61014082015201526004358152600960205260ff600160408320015460a81c1615611899576004358152600960205260408120906116c460026040519361163c85613174565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134e2565b6101208301526116d5600435613772565b6005811015611885576101606101c093600264ffffffffff931461187a575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117818d613157565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f4565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118e49036906004016130d9565b91906118ee61393e565b83925b8084106118fc578480f35b61190784828461349d565b359361191161393e565b848652600980855260ff90600190828260408b20015460a81c1615611beb57878952808752604089208281015460a01c8416156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd3576119918160005260096020526001600160a01b0360406000205416331490565b15611bb35761199f816136ba565b818a528289526119b4600260408c20016134e2565b906001600160801b0395868351168783161015611b9b57838c52848b5260408c205460f01c1615611b835791818a611a0585898f9a9998966119fb8c998387935116613225565b9501511690613225565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b6a575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaf8b85886140dc565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b13575b5050505050506001019291906118f1565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b56575b80808080611b02565b611b5f9061310a565b610524578438611b4d565b818601600160a01b60ff60a01b19825416179055611a6a565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c2161393e565b8183526009815260ff600160408520015460a81c1615611e1257611c4482613772565b6005811015611dfe5760048103611c6d5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8d576024836040519063fe19f19f60e01b82526004820152fd5b600214611de657611cb48260005260096020526001600160a01b0360406000205416331490565b15611dc7578183526009815260ff604084205460f01c1615611daf57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d57575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9b575b80611d28565b611da49061310a565b61049c578238611d95565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611efa575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f8a613078565b9080546001600160a01b0380821693338503611fdc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612025613078565b168015612042578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c576020612092600435613697565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120be61393e565b604051906120cb8261311e565b6120d3613078565b82526120dd61308e565b60208301526120ea6131eb565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c57506040516121448161313b565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161219a83613191565b61012435918216820361127b57826112739260209452610144358482015260e0820152613a03565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f59036906004016130d9565b90916024359081116104a05761220f9036906004016130d9565b61221761393e565b80830361261b57845b83811061222b578580f35b61223681858761349d565b359061224381868861349d565b35875260036020526001600160a01b0360408820541661226482858761349d565b35906001600160801b038216820361127b5761227e61393e565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156126035783895260036020526001600160a01b0360408a2054169182821415806125f3575b6125cf576122f6856140b1565b6001600160801b0381166001600160801b0383161161259f5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123878c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ab8160208401511692826040818351169201511690613225565b16111561256e575b86855260096020526001600160a01b036001604087200154166123e06001600160801b03841685836140dc565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612564575b6124fa575b8333141590816124ef575b816124e4575b50612472575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612220565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124cc575b808061243b565b6124d59061310a565b6124e05786386124c5565b8680fd5b905083141538612435565b843b1515915061242f565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612550575b5050612424565b6125599061310a565b610524578438612549565b50803b151561241f565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b3565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125fd8561399a565b156122e9565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614138565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257806126c883613772565b926005841015611885576002602094036126e9575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126dd565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a67576004359061274961393e565b8183526009815260ff600160408520015460a81c1615611e12578183526009815260ff600160408520015460a01c16156128d4576127868261399a565b15611dc75781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128ca575b50806128c2575b6128aa577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286f575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612857575080f35b60249060405190637e27328960e01b82526004820152fd5b61289085600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612805565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c5565b90501515386127be565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57612914366130a4565b60405191602083019383851067ffffffffffffffff86111761293f576110829460405285845261352a565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c661393e565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a145760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bd357612a3f8160005260096020526001600160a01b0360406000205416331490565b15611bb357612a4d816136ba565b93818452808352612a63600260408620016134e2565b916001600160801b0393848451168588161015611de65781865282815260ff604087205460f01c1615611daf57612ab1878683612aa78a9b838a9c9b9c5116613225565b9701511690613225565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c0a575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b3d8c84876140dc565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb9578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bfb575b81818080808480f35b612c049061310a565b81612bf2565b60018101600160a01b60ff60a01b19825416179055612af6565b503461064c57611082612c36366130a4565b91613254565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c9390613772565b90600582101561156f5760208215838115612cb4575b506040519015158152f35b600191501482612ca9565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257602091604082828152600985522060ff815460f01c1680612d4d575b612d24575b50506001600160801b0360405191168152f35b612d4692506001600160801b036002612d4092015416916136ba565b90613225565b3880612d11565b5060ff600182015460a01c1615612d0c565b503461064c57604036600319011261064c57612d79613078565b602435612d8581613697565b33151580612e45575b80612e1b575b612deb5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d94565b50336001600160a01b0382161415612d8e565b503461064c57602036600319011261064c576020612092600435613201565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f32575b602095868610811461148757858852879493929187908215611465575050600114612ed85750506113f7925003836131ad565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f1a5750506113f7935082010138806113e9565b80548389018501528794508693909201918101612f02565b93607f1693612ea5565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613006575b8115612fdc575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fce565b60005b8381106130435750506000910152565b8181015183820152602001613033565b9060209161306c81518092818552858086019101613030565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161293f57604052565b610100810190811067ffffffffffffffff82111761293f57604052565b6060810190811067ffffffffffffffff82111761293f57604052565b610180810190811067ffffffffffffffff82111761293f57604052565b610140810190811067ffffffffffffffff82111761293f57604052565b6040810190811067ffffffffffffffff82111761293f57604052565b90601f8019910116810190811067ffffffffffffffff82111761293f57604052565b67ffffffffffffffff811161293f57601f01601f191660200190565b604435906001600160801b038216820361127b57565b61320a81613697565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323e57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161347b575b5080613473575b61345c5786855260038152828486205416948733151593846133ac575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613374575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133465750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339582600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132e2565b9192938091509061341b575b156133c657908783926132b9565b8488876133e3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613440575b806133b857508782526005835233848684205416146133b8565b5085825260068352848220338352835260ff8583205416613426565b602487855190630da9b01360e01b82526004820152fd5b50600161329c565b9050151538613295565b6024604051633250574960e11b815260006004820152fd5b91908110156134ad5760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134d08261313b565b60006040838281528260208201520152565b906040516134ef8161313b565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b9190613537828285613254565b803b613544575b50505050565b6135a06001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613053565b03906020816000938185885af190829082613636575b50506135ed57826135c5614081565b80519190826135e65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361361e57503880808061353e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368f575b81613653602093836131ad565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b6565b3d9150613646565b8060005260036020526001600160a01b0360406000205416908115612857575090565b600090808252600a60205264ffffffffff9182604082205416421061376c5760096020526040812092835490808260c81c1691824210156137565761370b9394955060a01c168091039042036142fb565b9082815260096020526001600160801b03926137318460026040852001541680946143db565b92831161373e5750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613799575050600490565b805460f81c6137f2575460a01c64ffffffffff1642106137ec576137bc816136ba565b9060005260096020526001600160801b0380600260406000200154169116106000146137e757600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613934575b5080613929575b613912579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138da575b1692836138c4575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a0565b6138fb86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613898565b602486885190630da9b01360e01b82526004820152fd5b508181161515613837565b9050151538613830565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361397057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139df575b505082156139cd57505090565b9091506139da3392613201565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139c0565b90613a246001600160801b03604084015116602060e08501510151906141b3565b916001600160801b0383511660c082015190156140575764ffffffffff8151161561402d5764ffffffffff81511690604081019164ffffffffff8351169081811015613fed575050602081019064ffffffffff8251169081151580613fdb575b613f9a57505064ffffffffff90511664ffffffffff8251169081811015613f5a57505064ffffffffff8042169151169081811015613f1a575050600754926001600160801b0381511660405190613ada8261313b565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b3c88613174565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d3484875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613efc575b50600184016007556001600160a01b03602083015116801561348557613d84856001600160a01b03926137f9565b16613ecb57613daf6001600160a01b036060840151166001600160801b03835116903090339061428c565b6001600160801b0360208201511680613e9c575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e936001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec5906001600160a01b036060850151166001600160a01b0360e0860151511690339061428c565b38613dc3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d56565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a84565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140ac573d90614092826131cf565b916140a060405193846131ad565b82523d6000602084013e565b606090565b6140d9906140be81614138565b90600052600960205260026040600020015460801c90613225565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152614136916141316064836131ad565b61448a565b565b80600052600960205261415160026040600020016134e2565b816000526009602052604060002060ff600182015460a01c1660001461418457506001600160801b039150602001511690565b5460f81c61419657506140d9906136ba565b6140d991506001600160801b036040818351169201511690613225565b919091604051906141c382613191565b600091828152826020820152936001600160801b039283831691821561426d5767016345785d8a000080821161423657506141ff8591846143db565b16602087019281845211156142225750908261421d92511690613225565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061428182613191565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293f576141369260405261448a565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b7578285101561437b57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c5570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447957670de0b6b3a7640000908183101561444257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b5600080836020829551910182875af16144ae614081565b9084614526565b9081519182151592836144fe575b5050506144cd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144c3565b90614565575080511561453b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145b0575b614576575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004d983881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614996908162000402823960805181613da3015260a051818181612e810152613e430152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a7146131df57508063027b6744146131bc57806306fdde03146130f7578063081812fc146130d8578063095ea7b314612fdf5780631400ecec14612f3f5780631c1cdd4c14612eda5780631e99d56914612ebc57806323b872dd14612ea45780632fe4304114612e6957806332fbe22b14612d1157806340e58ee514612a73578063425d30dd14612a2257806342842e0e146129e857806342966c681461280d57806344267570146127e65780634857501f146127705780634869e12d146127355780634cc55e11146122b95780636352211e146122895780636d0cee751461228957806370a082311461221957806375829def146121865780637cad6cd11461208c5780637de6b1db14611e655780637f5799f914611e0a5780638659c27014611ab0578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a61330e565b91604435926001600160801b038085169182860361063f5761029a613d99565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f89614546565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614571565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138b5565b90808483015116918180825116916040015116610395916134f6565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886146d6565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b61049890613417565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b61052090613417565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8896144ad565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f61330e565b9161074981614546565b92610752613d99565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f89614546565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d6132f8565b604061082761330e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614546565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b5034610644576020366003190112610644576004356000602060405161096781613464565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a783613464565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613a77565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a656040519282849384528301906132d3565b0390f35b909192503d8082843e610a7c8184613480565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134a2565b93610ac06040519586613480565b838552858484010111610644575090610ade918480850191016132b0565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b1361330e565b610b1b613d99565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b6286614546565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c54565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613d99565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a614546565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c614571565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138b5565b90610cec818a84015116928260408183511692015116906134f6565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d338186886146d6565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df990613417565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d90613417565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a6144ad565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b6132f8565b61108361330e565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134a2565b936110c06040519586613480565b8585523660248783010111610ae657856110eb9660246020930183880137850101526044359161390a565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613bcd565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d6132f8565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b505061131192500383613480565b610a656040519282849384528301906132d3565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613bcd565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613d99565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a75760249061152886613780565b956115366040519788613480565b8652878601920101913683116104a757905b86838310611743575050505081519061156082613780565b9261156e6040519485613480565b828452601f1961157d84613780565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613a9a565b51511683808b6115b785613a9a565b51015116880116604051916115cb83613464565b82528a8201526115da88613a9a565b526115e487613a9a565b5060019260015b8381106116b6575050505050611603856004016138e9565b91611610602487016138e9565b9161161d60448801613823565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d016138fd565b948161166360a48c016138fd565b976040519d8e6133fa565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016137ce565b610100820152613df5565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613aa7565b51511696600019890190613aa7565b51015116916116ea868a613aa7565b510151160116604051916116fd83613464565b82528d82015261170d828c613aa7565b52611718818b613aa7565b50016115eb565b60405161172b81613464565b60008152600083820152828289010152018790611581565b6040916117503685613798565b815201910190611548565b503461064457602036600319011261064457606061014060405161177e8161342b565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201526040516117bd81613448565b84815284602082015284604082015261012082015201526004358152600960205260ff600160408320015460a81c1615611a985760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a82576118ae9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138b5565b6101208301526118bf600435613bcd565b6005811015611a6e5761014092600261198b9214611a63575b6101208101516001600160a01b0360a08301511664ffffffffff60408401511694606084015115159061010085015115159260c086015115159160e08701511515936001600160a01b03885116996080604064ffffffffff60208c015116946004358152600a602052209901511515926040519b6119558d61342b565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152613837565b82820152610a65604051928392602084526001600160a01b03815116602085015264ffffffffff602082015116604085015264ffffffffff60408201511660608501526060810151151560808501526080810151151560a08501526001600160a01b0360a08201511660c085015260c0810151151560e085015260e08101511515610100850152610100810151151561012085015261012081015160406001600160801b039182815116858801528260208201511661016088015201511661018085015201516101a0808401526101c083019061339e565b8260608201526118d8565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611ae390369060040161336d565b9190611aed613d99565b83925b808410611afb578480f35b611b068482846137fd565b3593611b10613d99565b848652600980855260ff90600190828260408b20015460a81c1615611df357878952808752604089208281015460a01c841615611b5f5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611ddb57611b908160005260096020526001600160a01b0360406000205416331490565b15611dbb57611b9e81613abb565b818a52828952611bb3600260408c20016138b5565b906001600160801b0395868351168783161015611da357838c52848b5260408c205460f01c1615611d8b5791818a611c0485898f9a999896611bfa8c9983879351166134f6565b95015116906134f6565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611d72575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cb78b85886146d6565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d1b575b505050505050600101929190611af0565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d5e575b80808080611d0a565b611d6790613417565b61052b578438611d55565b818601600160a01b60ff60a01b19825416179055611c69565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e5192610a659452600a60205220613837565b60405191829160208352602083019061339e565b503461064457602080600319360112610ae65760043590611e84613d99565b8183526009815260ff600160408520015460a81c161561207557611ea782613bcd565b60058110156120615760048103611ed05760248360405190634a5541ef60e01b82526004820152fd5b60038103611ef0576024836040519063fe19f19f60e01b82526004820152fd5b60021461204957611f178260005260096020526001600160a01b0360406000205416331490565b1561202a578183526009815260ff604084205460f01c161561201257818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611fba575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611ffe575b80611f8b565b61200790613417565b6104a3578238611ff8565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a3578183541633810361215d575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121495760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121a06132f8565b9080546001600160a01b03808216933385036121f2576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361223b6132f8565b168015612258578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122a8600435613a77565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576122ec90369060040161336d565b90916024359081116104a75761230690369060040161336d565b61230e613d99565b8083036126fe57845b838110612322578580f35b61232d8185876137fd565b359061233a8186886137fd565b35875260036020526001600160a01b0360408820541661236361235e8386886137fd565b613823565b9061236c613d99565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b038216156126e65783895260036020526001600160a01b0360408a2054169182821415806126d6575b6126b2576123e485614546565b6001600160801b0381166001600160801b038316116126825750908992918584526009602052604084209261246a6001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961244c87608094851c614571565b938c8b52600960205260408b2001938454931b1691161781556138b5565b6001600160801b0361248e81602084015116928260408183511692015116906134f6565b161115612651575b86855260096020526001600160a01b036001604087200154166124c36001600160801b03841685836146d6565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612647575b6125dd575b8333141590816125d2575b816125c7575b50612555575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612317565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125af575b808061251e565b6125b890613417565b6125c35786386125a8565b8680fd5b905083141538612518565b843b15159150612512565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612633575b5050612507565b61263c90613417565b61052b57843861262c565b50803b1515612502565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612496565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506126e0856144ad565b156123d7565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614730565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c161561207557806127ab83613bcd565b926005841015611a6e576002602094036127cc575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127c0565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae6576004359061282c613d99565b8183526009815260ff600160408520015460a81c1615612075578183526009815260ff600160408520015460a01c16156129b757612869826144ad565b1561202a5781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129ad575b50806129a5575b61298d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612952575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161293a575080f35b60249060405190637e27328960e01b82526004820152fd5b61297385600052600560205260406000206001600160a01b03198154169055565b8060005260048252604060002060001981540190556128e8565b60248360405190630da9b01360e01b82526004820152fd5b5060006128a8565b90501515386128a1565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610644576129f736613338565b60405191602083019383851067ffffffffffffffff861117611a82576110eb9460405285845261390a565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612a93613d99565b81815260099283815260ff600160408420015460a81c1615612cfa5782825283815260408220600181015460a01c60ff1615612ae15760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611ddb57612b0c8160005260096020526001600160a01b0360406000205416331490565b15611dbb57612b1a81613abb565b93818452808352612b30600260408620016138b5565b916001600160801b03938484511685881610156120495781865282815260ff604087205460f01c161561201257612b7e878683612b748a9b838a9c9b9c51166134f6565b97015116906134f6565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612ce0575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c138c84876146d6565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612c8f578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612cd1575b81818080808480f35b612cda90613417565b81612cc8565b60018101600160a01b60ff60a01b19825416179055612bc3565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d50613d99565b60405193612d5d856133fa565b612d6984600401613324565b8552612d7760248501613324565b6020860152612d88604485016134be565b604086015260648401356001600160a01b03811681036104a3576060860152612db3608485016133ed565b6080860152612dc460a485016133ed565b60a0860152612dd560c4850161376e565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e0281613780565b93612e106040519586613480565b8185526024602086019260061b820101933685116106445750602401905b838210612e505760206116ae886116a3898960e08401526101043691016137ce565b82604091612e5e3685613798565b815201910190612e2e565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eb636613338565b91613525565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f1390613bcd565b9060058210156114895760208215838115612f34575b506040519015158152f35b600191501482612f29565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c161561207557602091604082828152600985522060ff815460f01c1680612fcd575b612fa4575b50506001600160801b0360405191168152f35b612fc692506001600160801b036002612fc09201541691613abb565b906134f6565b3880612f91565b5060ff600182015460a01c1615612f8c565b503461064457604036600319011261064457612ff96132f8565b60243561300581613a77565b331515806130c5575b8061309b575b61306b5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615613014565b50336001600160a01b038216141561300e565b50346106445760203660031901126106445760206122a86004356134d2565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131b2575b60209586861081146113a15785885287949392918790821561137f57505060011461315857505061131192500383613480565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061319a57505061131193508201013880611303565b80548389018501528794508693909201918101613182565b93607f1693613125565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613286575b811561325c575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613255565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061324e565b60005b8381106132c35750506000910152565b81810151838201526020016132b3565b906020916132ec815180928185528580860191016132b0565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133be575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133b0565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611a8257604052565b67ffffffffffffffff8111611a8257604052565b610160810190811067ffffffffffffffff821117611a8257604052565b6060810190811067ffffffffffffffff821117611a8257604052565b6040810190811067ffffffffffffffff821117611a8257604052565b90601f8019910116810190811067ffffffffffffffff821117611a8257604052565b67ffffffffffffffff8111611a8257601f01601f191660200190565b35906001600160801b038216820361063f57565b6134db81613a77565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161350f57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561375657600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161374c575b5080613744575b61372d57868552600381528284862054169487331515938461367d575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613645575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136175750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61366682600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135b3565b919293809150906136ec575b15613697579087839261358a565b8488876136b4576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613711575b806136895750878252600583523384868420541614613689565b5085825260068352848220338352835260ff85832054166136f7565b602487855190630da9b01360e01b82526004820152fd5b50600161356d565b9050151538613566565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611a825760051b60200190565b919082604091031261063f576040516137b081613464565b60206137c98183956137c1816134be565b85520161376e565b910152565b919082604091031261063f576040516137e681613464565b60208082946137f481613324565b84520135910152565b919081101561380d5760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461384381613780565b926040936138546040519182613480565b82815280946020809201926000526020600020906000935b85851061387b57505050505050565b6001848192845161388b81613464565b64ffffffffff87546001600160801b038116835260801c168382015281520193019401939161386c565b906040516138c281613448565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b9190613917828285613525565b803b613924575b50505050565b6139806001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906132d3565b03906020816000938185885af190829082613a16575b50506139cd57826139a5614516565b80519190826139c65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000016036139fe57503880808061391e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613a6f575b81613a3360209383613480565b81010312610ae65751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106445750903880613996565b3d9150613a26565b8060005260036020526001600160a01b036040600020541690811561293a575090565b80511561380d5760200190565b805182101561380d5760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613adf60408220613837565b9185856020613aed86613a9a565b5101511611613bc45781526009602052604081208585825460c81c161115613bae57506001600160801b039485613b2384613a9a565b5151169583519260019360011015613b9a5750949392919084602060408501510151169581866001985b161115613b5e575050505050505090565b909181879881613b728798999a8598613aa7565b5151160116970191868087613b878689613aa7565b5101511697829392919796959498613b4d565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613bf4575050600490565b805460f81c613c4d575460a01c64ffffffffff164210613c4757613c1781613abb565b9060005260096020526001600160801b038060026040600020015416911610600014613c4257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613d8f575b5080613d84575b613d6d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d35575b169283613d1f575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613cfb565b613d5686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613cf3565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c92565b9050151538613c8b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dcb57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e176001600160801b03604084015116602061010085015101519061458c565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144835781518015614459577f00000000000000000000000000000000000000000000000000000000000000008111614428575064ffffffffff6020613e7a84613a9a565b510151168110156143d15750600090819082815184905b808210614340575050505064ffffffffff421664ffffffffff82168110156143005750506001600160801b03168082036142c9575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061402d8951996000198b0190613aa7565b51015160c81b169560f01b16911617171717845560005b818110614224575050600185016007556001600160a01b0360208301511680156137565761407a866001600160a01b0392613c54565b166141f3576140a56001600160a01b036060840151166001600160801b038351169030903390614665565b6001600160801b03602082015116806141c3575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141b861419960808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141428c613464565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061339e565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b6141ed906001600160a01b036060850151166001600160a01b036101008601515116903390614665565b386140b9565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142418160e0870151613aa7565b51825468010000000000000000811015611a82576001810180855581101561380d57600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614044565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614364906001600160801b0361435b8588613aa7565b51511690614571565b9364ffffffffff8060206143788685613aa7565b5101511694168085111561439457506001849301909291613e91565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff60206143e284613a9a565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156144f2575b505082156144e057505090565b9091506144ed33926134d2565b161490565b60ff92945090604091815260066020528181203382526020522054169138806144d3565b3d15614541573d90614527826134a2565b916145356040519384613480565b82523d6000602084013e565b606090565b61456e9061455381614730565b90600052600960205260026040600020015460801c906134f6565b90565b9190916001600160801b038080941691160191821161350f57565b9190916040519061459c82613464565b600091828152826020820152936001600160801b03928383169182156146465767016345785d8a000080821161460f57506145d8859184614847565b16602087019281845211156145fb575090826145f6925116906134f6565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061465a82613464565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a82576146d4926040526147ab565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146d49161472b606483613480565b6147ab565b80600052600960205261474960026040600020016138b5565b816000526009602052604060002060ff600182015460a01c1660001461477c57506001600160801b039150602001511690565b5460f81c61478e575061456e90613abb565b61456e91506001600160801b0360408183511692015116906134f6565b6001600160a01b0316906147d6600080836020829551910182875af16147cf614516565b90846148f6565b90815191821515928361481f575b5050506147ee5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae657602001519081159182150361064457503880806147e4565b909190600019838209838202918280831092039180830392146148e557670de0b6b3a764000090818310156148ae57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b90614935575080511561490b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614980575b614946575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561493e56fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004dcf3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149cd908162000402823960805181613dda015260a051818181612eb80152613e7a0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613dd0565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961457d565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610343916145a8565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a8861470d565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8896144e4565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b916107498161457d565b92610752613dd0565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961457d565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b85761089360209161457d565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613dd0565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b628661457d565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c8b565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613dd0565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a61457d565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c6145a8565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d3381868861470d565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a6144e4565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613c04565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613c04565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613dd0565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613e2c565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613c04565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613dd0565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613dd0565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b858861470d565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613dd0565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613c04565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613dd0565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613dd0565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b8561457d565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c6145a8565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b038416858361470d565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b50612717856144e4565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614767565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613c04565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613dd0565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a0826144e4565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613dd0565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c848761470d565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613dd0565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613c04565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc61454d565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613b166040822061386e565b9185856020613b2486613ad1565b5101511611613bfb5781526009602052604081208585825460c81c161115613be557506001600160801b039485613b5a84613ad1565b5151169583519260019360011015613bd15750949392919084602060408501510151169581866001985b161115613b95575050505050505090565b909181879881613ba98798999a8598613ade565b5151160116970191868087613bbe8689613ade565b5101511697829392919796959498613b84565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613c2b575050600490565b805460f81c613c84575460a01c64ffffffffff164210613c7e57613c4e81613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c7957600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613dc6575b5080613dbb575b613da4579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d6c575b169283613d56575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d32565b613d8d86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d2a565b602486885190630da9b01360e01b82526004820152fd5b508181161515613cc9565b9050151538613cc2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e0257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e4e6001600160801b0360408401511660206101008501510151906145c3565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144ba5781518015614490577f0000000000000000000000000000000000000000000000000000000000000000811161445f575064ffffffffff6020613eb184613ad1565b510151168110156144085750600090819082815184905b808210614377575050505064ffffffffff421664ffffffffff82168110156143375750506001600160801b0316808203614300575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140648951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b81811061425b575050600185016007556001600160a01b03602083015116801561378d576140b1866001600160a01b0392613c8b565b1661422a576140dc6001600160a01b036060840151166001600160801b03835116903090339061469c565b6001600160801b03602082015116806141fa575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141ef6141d060808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141798c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b614224906001600160a01b036060850151166001600160a01b03610100860151511690339061469c565b386140f0565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142788160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b169216171790550161407b565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b919350919361439b906001600160801b036143928588613ade565b515116906145a8565b9364ffffffffff8060206143af8685613ade565b510151169416808511156143cb57506001849301909291613ec8565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061441984613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614529575b5050821561451757505090565b9091506145243392613509565b161490565b60ff929450906040918152600660205281812033825260205220541691388061450a565b3d15614578573d9061455e826134d9565b9161456c60405193846134b7565b82523d6000602084013e565b606090565b6145a59061458a81614767565b90600052600960205260026040600020015460801c9061352d565b90565b9190916001600160801b038080941691160191821161354657565b919091604051906145d38261349b565b600091828152826020820152936001600160801b039283831691821561467d5767016345785d8a0000808211614646575061460f85918461487e565b16602087019281845211156146325750908261462d9251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146918261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761470b926040526147e2565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261470b916147626064836134b7565b6147e2565b80600052600960205261478060026040600020016138ec565b816000526009602052604060002060ff600182015460a01c166000146147b357506001600160801b039150602001511690565b5460f81c6147c557506145a590613af2565b6145a591506001600160801b03604081835116920151169061352d565b6001600160a01b03169061480d600080836020829551910182875af161480661454d565b908461492d565b908151918215159283614856575b5050506148255750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061481b565b9091906000198382098382029182808310920391808303921461491c57670de0b6b3a764000090818310156148e557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061496c575080511561494257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149b7575b61497d575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561497556fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615f2090816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661570a565b91601e604660ff61030b8460146050848d60081c1606011661570a565b981606011661570a565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615091565b16906151fa565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff8091169116615545565b610120516101805190929161059d602161053a6064610533818706615a17565b950461570a565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615b23565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b60008152866159eb565b156147c9576090945b6106fa8661570a565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b6109ec82615e9d565b808211156147c15750945b610a0287870161570a565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615e1f565b610d1b82615e9d565b808211156147b95750935b610d326028860161570a565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615190565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615aea565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615aea565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615aea565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615aea565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615190565b92611ce9611ce3614d0b565b896159eb565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615d63565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615d63565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615dcb565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615dcb565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461570a565b9461570a565b9761570a565b9161570a565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561570a565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561570a565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b610160516141049061585b565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e081905261585b565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b906159eb565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d84876159da565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa92831561508657600093615063575b50815192614eb6846149de565b60118452614eeb6020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159eb565b15614f295750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614f1f836149de565b600d835282015290565b614f668351614f37816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159eb565b15614fa45750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614f9a836149de565b600e835282015290565b614fe18351614fb2816149de565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159eb565b1561501f5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191615015836149de565b600f835282015290565b61505f9083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61507f91933d8091833e61507781836149fa565b810190614bce565b9138614ea9565b82513d6000823e3d90fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150c9816149de565b6000928392839251915afa6150dc614b9e565b9080615113575b1561510f5760208180518101031261510b57602001519060ff82168203615108575090565b80fd5b5080fd5b5090565b5060208151146150e3565b6040519061512b826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615164826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151f89294936040519586926020946151b281518092888089019101614909565b84016151c682518093888085019101614909565b016151d982518093878085019101614909565b016151ec82518093868085019101614909565b010380855201836149fa565b565b801561550a57600091806154e5575090505b600190808281101561527657505050615223615157565b614c2d602260405183615240829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c6800011156154885760409081519060a0820182811067ffffffffffffffff821117614402578084526152ad8161498a565b6000815282528251906152bf826149de565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152f9816149de565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615330816149de565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615368816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545c575b508451946153af866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615449575050505061542a615430917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615425866149de565b61570a565b91615a17565b916005851015614b6c57614c2d9460051b015192615190565b81810184015188820185015283016153e0565b9591926103e89081851061547f57508680916064600a870406950493019661539d565b939296506153a2565b505061549261511e565b614c2d6028604051836154af829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a9182156154f657500461520c565b80634e487b7160e01b602492526012600452fd5b5050604051615518816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155ad575061555a615157565b614c2d602660405183615577829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f811161567c576001810361563957614c2d60206156016040516155d2816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570a565b60405193816156198693518092868087019101614909565b820161562d82518093868085019101614909565b010380845201826149fa565b614c2d602061560160405161564d816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570a565b5061568561511e565b614c2d602a604051836156a2829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b906156e282614b82565b6156ef60405191826149fa565b8281528092615700601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561584d575b506d04ee2d6d415b85acef81000000008083101561583e575b50662386f26fc100008083101561582f575b506305f5e10080831015615820575b5061271080831015615811575b506064821015615801575b600a809210156157f7575b6001908160216157a2600187016156d8565b95860101905b6157b4575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f2579190826157a8565b6157ad565b9160010191615790565b9190606460029104910191615785565b6004919392049101913861577a565b6008919392049101913861576d565b6010919392049101913861575e565b6020919392049101913861574c565b604093508104915038615733565b8051156159c65760405161586e816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159b05760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159b05761590d906002959492951b6156d8565b936020850193839284518501935b84811061595d57505050505060039051068060011461594a5760021461593f575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061591b565b634e487b7160e01b600052601160045260246000fd5b506040516159d38161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615a01575050505090565b60209293945082012092012014388080806157ad565b80615a2957506040516159d38161498a565b600a811015615a8e57615a3b9061570a565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7e8151809260208686019101614909565b81010360028101845201826149fa565b615a979061570a565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ada8151809260208686019101614909565b81010360018101845201826149fa565b60405190615af7826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d5557615b31615aea565b906127109081039081116159b057614c2d91615b4f6101369261570a565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bdb815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c6382518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cc482518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159d38161498a565b60306151f8919392936040519481615d85879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dbc8251809360208785019101614909565b010360108101855201836149fa565b60256151f8919392936040519481615ded879351809260208087019101614909565b820164010714051160dd1b6020820152615e108251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e9557906000916000915b818310615e4457505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e7787856159da565b511614615e8d575b600d01936001019190615e32565b849350615e7f565b505050600090565b60009080518015615e9557906000916000915b818310615ec25750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ef587856159da565b511614615f0b575b601001936001019190615eb0565b849350615efd56fea164736f6c6343000817000a"; diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 172f72780..620b5ac3e 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -122,8 +122,9 @@ contract SablierV2LockupDynamic is isTransferable: lockupStream.isTransferable, isDepleted: lockupStream.isDepleted, isStream: lockupStream.isStream, - sender: lockupStream.sender, + recipient: _ownerOf(streamId), segments: _segments[streamId], + sender: lockupStream.sender, startTime: lockupStream.startTime, wasCanceled: lockupStream.wasCanceled }); diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index a88ac2b4d..8af9d3d97 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -112,6 +112,7 @@ contract SablierV2LockupLinear is isTransferable: lockupStream.isTransferable, isDepleted: lockupStream.isDepleted, isStream: lockupStream.isStream, + recipient: _ownerOf(streamId), sender: lockupStream.sender, startTime: lockupStream.startTime, wasCanceled: lockupStream.wasCanceled diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index bfd35ab77..f27cb7f30 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -106,6 +106,7 @@ contract SablierV2LockupTranched is isTransferable: lockupStream.isTransferable, isDepleted: lockupStream.isDepleted, isStream: lockupStream.isStream, + recipient: _ownerOf(streamId), sender: lockupStream.sender, startTime: lockupStream.startTime, tranches: _tranches[streamId], diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 860623037..f7082625f 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -179,9 +179,10 @@ library LockupDynamic { /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the segments. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the segments. struct StreamLD { address sender; + address recipient; uint40 startTime; uint40 endTime; bool isCancelable; @@ -264,9 +265,10 @@ library LockupLinear { /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the cliff value. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the cliff value. struct StreamLL { address sender; + address recipient; uint40 startTime; bool isCancelable; bool wasCanceled; @@ -342,9 +344,10 @@ library LockupTranched { /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the tranches. + /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the tranches. struct StreamLT { address sender; + address recipient; uint40 startTime; uint40 endTime; bool isCancelable; diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index d831ad648..3cb8057e4 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -187,6 +187,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.segments, params.segments, "segments"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.startTime, "startTime"); diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index 603227a76..4287339da 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -186,6 +186,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.range.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol index 173b6e112..114cbefb0 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/fork/LockupTranched.t.sol @@ -189,6 +189,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.tranches, params.tranches, "tranches"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.startTime, "startTime"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 460bd39aa..7cd7869d1 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -108,6 +108,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, users.recipient, "recipient"); assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); assertEq(actualStream.startTime, range.start, "startTime"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index c1265443d..a5f279d39 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -269,6 +269,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.segments, params.segments, "segments"); assertEq(actualStream.startTime, range.start, "startTime"); diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 133b9e88a..bc53ce6fd 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -182,6 +182,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.range.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 1c95cbee3..6a1468668 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -108,6 +108,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.tranches, vars.tranchesWithTimestamps, "tranches"); assertEq(actualStream.sender, users.sender, "sender"); assertEq(actualStream.startTime, range.start, "startTime"); diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 3c673940f..4b25dd2e0 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -272,6 +272,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.tranches, params.tranches, "tranches"); assertEq(actualStream.startTime, range.start, "startTime"); diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 5f2395315..74cf9d617 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -51,6 +51,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { assertEq(a.isDepleted, b.isDepleted, "isDepleted"); assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.recipient, b.recipient, "recipient"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); @@ -64,6 +65,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { assertEq(a.isDepleted, b.isDepleted, "isDepleted"); assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.recipient, b.recipient, "recipient"); assertEq(a.segments, b.segments, "segments"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); @@ -78,6 +80,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { assertEq(a.isDepleted, b.isDepleted, "isDepleted"); assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.recipient, b.recipient, "recipient"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); assertEq(a.tranches, b.tranches, "tranches"); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 10de17ebd..e755694e2 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -96,6 +96,7 @@ contract Defaults is Constants { isDepleted: false, isStream: true, isTransferable: true, + recipient: users.recipient, segments: segments(), sender: users.sender, startTime: START_TIME, @@ -117,6 +118,7 @@ contract Defaults is Constants { isTransferable: true, isDepleted: false, isStream: true, + recipient: users.recipient, sender: users.sender, startTime: START_TIME, wasCanceled: false @@ -136,6 +138,7 @@ contract Defaults is Constants { isDepleted: false, isStream: true, isTransferable: true, + recipient: users.recipient, sender: users.sender, startTime: START_TIME, tranches: tranches(), From 7b73025d2abb076319a5494b300d144fb27e9fdb Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 14 Mar 2024 17:02:15 +0000 Subject: [PATCH 064/132] docs: rename MAX_FEE to MAX_BROKER_FEE in NatSpec --- src/interfaces/ISablierV2LockupTranched.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 2dd6c3f61..bdbd8a98e 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -114,7 +114,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// Requirements: /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. - /// - If set, `params.broker.fee` must not be greater than `MAX_FEE`. + /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. /// - `params.tranches` must have at least one tranche, but not more than `MAX_TRANCHE_COUNT`. /// - `params.startTime` must be less than the first tranche's timestamp. /// - The tranche timestamps must be arranged in ascending order. From ce4915f7f7bb57eba52b315d54b80c804d5d805c Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 16 Mar 2024 20:50:02 +0000 Subject: [PATCH 065/132] chore: rename custom-errors to gas-custom-errors in solhint --- .solhint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.solhint.json b/.solhint.json index 713a70b3f..a40b9ff6b 100644 --- a/.solhint.json +++ b/.solhint.json @@ -6,9 +6,9 @@ "compiler-version": ["error", ">=0.8.22"], "contract-name-camelcase": "off", "const-name-snakecase": "off", - "custom-errors": "off", "func-name-mixedcase": "off", "func-visibility": ["error", { "ignoreConstructors": true }], + "gas-custom-errors": "off", "max-line-length": ["error", 123], "named-parameters-mapping": "warn", "no-empty-blocks": "off", From be1dea483581eefa4a048369853db15404fe1e07 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Sun, 17 Mar 2024 16:33:32 +0200 Subject: [PATCH 066/132] feat: disallow zero startTime in dynamic and tranched (#852) test: when start time is zero in create function from dynamic and tranched test: fuzz start time starting from 1 test: move common invariants in Lockup test: remove no longer needed invariants chore: update Precompiles --- precompiles/Precompiles.sol | 6 +- src/interfaces/ISablierV2LockupDynamic.sol | 2 +- src/interfaces/ISablierV2LockupLinear.sol | 6 +- src/interfaces/ISablierV2LockupTranched.sol | 2 +- src/libraries/Errors.sol | 6 +- src/libraries/Helpers.sol | 12 +++- test/fork/LockupDynamic.t.sol | 2 +- test/fork/LockupTranched.t.sol | 2 +- .../createWithTimestamps.t.sol | 22 ++++++ .../createWithTimestamps.tree | 71 ++++++++++--------- .../createWithTimestamps.t.sol | 19 ++++- .../createWithTimestamps.t.sol | 22 ++++++ .../createWithTimestamps.tree | 71 ++++++++++--------- .../lockup-dynamic/createWithTimestamps.t.sol | 3 +- .../lockup-linear/createWithTimestamps.t.sol | 1 + .../createWithTimestamps.t.sol | 3 +- .../lockup-dynamic/createWithTimestamps.t.sol | 4 ++ .../lockup-linear/createWithTimestamps.t.sol | 4 ++ .../createWithTimestamps.t.sol | 4 ++ test/invariant/Lockup.t.sol | 18 +++++ test/invariant/LockupDynamic.t.sol | 20 ------ test/invariant/LockupLinear.t.sol | 20 ------ test/invariant/LockupTranched.t.sol | 20 ------ .../handlers/LockupDynamicCreateHandler.sol | 2 +- .../handlers/LockupTranchedCreateHandler.sol | 2 +- 25 files changed, 195 insertions(+), 149 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 76da39f79..472588760 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -25,11 +25,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f1962005a0b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156099081620004028239608051816139a6015260a051818181610c9f0152613a670152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab82614197565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614197565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614197565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a6145d5565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161462f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d83826140fe565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d85886145d5565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614167565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a614197565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be916141bf565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b878252855220015416946131518189886145d5565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a6140fe565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e6134378361462f565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b916141bf565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c886145d5565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b6140fe565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a8906142ab565b90565b6137a8906141da565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b03604084015116602061010085015101519061448b565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140d457815180156140aa577f00000000000000000000000000000000000000000000000000000000000000008111614079575064ffffffffff6040613a9e846139f8565b510151168110156140225750600090819082815184905b808210613f91575050505064ffffffffff421664ffffffffff8216811015613f515750506001600160801b0316808203613f1a575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c518951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e48575050600185016007556001600160a01b03602083015116801561078d57613c9e866001600160a01b0392613857565b16613e1757613cc96001600160a01b036060840151166001600160801b038351169030903390614564565b6001600160801b0360208201511680613de7575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613ddc613dbd60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d668c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e11906001600160a01b036060850151166001600160a01b036101008601515116903390614564565b38613cdd565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e658160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c68565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fb5906001600160801b03613fac8588613a05565b515116906141bf565b9364ffffffffff806040613fc98685613a05565b51015116941680851115613fe557506001849301909291613ab5565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614033846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614143575b5050821561413157505090565b90915061413e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614124565b3d15614192573d90614178826129b2565b916141866040519384612990565b82523d6000602084013e565b606090565b6137a8906141a48161462f565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff61420f600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146aa565b91808252600a602052604082208054156142975790829167ffffffffffffffff9352614269602083205482845260096020526142646001600160801b03968760026040882001541696879360801c169061479a565b614808565b92831361427f57505061427b906148f2565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff80421660008381526009602052604091828220908351916142d183612973565b80549661012061435760026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a60205261436e858520612df7565b918496808761437c866139f8565b5101511692828288955b161061445557509161440a6142649284888161440f98976001600160801b039e8f6143b1898c613a05565b5151169d8e9a67ffffffffffffffff60206143cc8c84613a05565b510151169984836143dd8385613a05565b5101511696508015614449576143f99293506000190190613a05565b5101511680925b03169203166146aa565b61479a565b92831361442857505061442283916148f2565b16011690565b5160200151929392831692841683101591506144449050575090565b905090565b50505051168092614400565b8093986001600160801b03908161446c8c89613a05565b51511601169801928282808a614482888a613a05565b51015116614386565b9190916040519061449b82612943565b600091828152826020820152936001600160801b03928383169182156145455767016345785d8a000080821161450e57506144d78591846154ba565b16602087019281845211156144fa575090826144f592511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061455982612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb576145d39260405261492e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526145d39161462a606483612990565b61492e565b8060005260096020526146486002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c1660001461467b57506001600160801b039150602001511690565b5460f81c61468d57506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b600160ff1b808214908115614790575b5061476657600081121561475d576146e3816000035b60008412156147565783600003906149ca565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f57600019911813156147195790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149ca565b6146e3816146d0565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ba565b806147b557506147b057670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146148025750806147da575050670de0b6b3a764000090565b670de0b6b3a764000081146147fe576147f9906142646137a893614ac4565b614c06565b5090565b91505090565b600160ff1b8082149081156148e8575b506148be5760008112156148b557614841816000035b60008412156148ae5783600003906154ba565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161487757600019911813156147195790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ba565b6148418161482e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614818565b600081126148fd5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614959600080836020829551910182875af1614952614167565b9084615569565b9081519182151592836149a2575b5050506149715750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614967565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a865782851015614a4a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a94570490565b634e487b7160e01b600052601260045260246000fd5b8015614a94576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bd557670de0b6b3a764000092838112614bb257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614ba657506706f05b59d3b20000905b848213614b7a5750505050500290565b808391020590671bc16d674ec80000821215614b99575b831d90614b6a565b8091950194831d90614b91565b93505093925050020290565b6000199392508015614a94576ec097ce7bc90715b34b9f10000000000591614ae5565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c355768033dd1780914b9711419811261384a57614c2c90600003614c06565b6137a890614aaa565b680a688906bd8affffff811361548957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661536c575b66ff0000000000008316615264575b65ff00000000008316615164575b64ff00000000831661506c575b63ff0000008316614f7c575b62ff00008316614e94575b61ff008316614db4575b60ff8316614cdd575b02911c60bf031c90565b60808316614da2575b838316614d90575b60208316614d7e575b60108316614d6c575b60088316614d5a575b60048316614d48575b60028316614d36575b6001831615614cd3576801000000000000000102831c614cd3565b6801000000000000000102831c614d1b565b6801000000000000000302831c614d12565b6801000000000000000602831c614d09565b6801000000000000000b02831c614d00565b6801000000000000001602831c614cf7565b6801000000000000002c02831c614cee565b6801000000000000005902831c614ce6565b6180008316614e82575b6140008316614e70575b6120008316614e5e575b6110008316614e4c575b6108008316614e3a575b6104008316614e28575b6102008316614e16575b610100831615614cca57680100000000000000b102831c614cca565b6801000000000000016302831c614dfa565b680100000000000002c602831c614df0565b6801000000000000058c02831c614de6565b68010000000000000b1702831c614ddc565b6801000000000000162e02831c614dd2565b68010000000000002c5d02831c614dc8565b680100000000000058b902831c614dbe565b628000008316614f6a575b624000008316614f58575b622000008316614f46575b621000008316614f34575b620800008316614f22575b620400008316614f10575b620200008316614efe575b62010000831615614cc0576801000000000000b17202831c614cc0565b680100000000000162e402831c614ee1565b6801000000000002c5c802831c614ed6565b68010000000000058b9102831c614ecb565b680100000000000b172102831c614ec0565b68010000000000162e4302831c614eb5565b680100000000002c5c8602831c614eaa565b6801000000000058b90c02831c614e9f565b6380000000831661505a575b63400000008316615048575b63200000008316615036575b63100000008316615024575b63080000008316615012575b63040000008316615000575b63020000008316614fee575b6301000000831615614cb55768010000000000b1721802831c614cb5565b6801000000000162e43002831c614fd0565b68010000000002c5c86002831c614fc4565b680100000000058b90c002831c614fb8565b6801000000000b17217f02831c614fac565b680100000000162e42ff02831c614fa0565b6801000000002c5c85fe02831c614f94565b68010000000058b90bfc02831c614f88565b6480000000008316615152575b6440000000008316615140575b642000000000831661512e575b641000000000831661511c575b640800000000831661510a575b64040000000083166150f8575b64020000000083166150e6575b640100000000831615614ca957680100000000b17217f802831c614ca9565b68010000000162e42ff102831c6150c7565b680100000002c5c85fe302831c6150ba565b6801000000058b90bfce02831c6150ad565b68010000000b17217fbb02831c6150a0565b6801000000162e42fff002831c615093565b68010000002c5c8601cc02831c615086565b680100000058b90c0b4902831c615079565b658000000000008316615252575b654000000000008316615240575b65200000000000831661522e575b65100000000000831661521c575b65080000000000831661520a575b6504000000000083166151f8575b6502000000000083166151e6575b65010000000000831615614c9c576801000000b17218355102831c614c9c565b680100000162e430e5a202831c6151c6565b6801000002c5c863b73f02831c6151b8565b68010000058b90cf1e6e02831c6151aa565b680100000b1721bcfc9a02831c61519c565b68010000162e43f4f83102831c61518e565b680100002c5c89d5ec6d02831c615180565b6801000058b91b5bc9ae02831c615172565b6680000000000000831661535a575b66400000000000008316615348575b66200000000000008316615336575b66100000000000008316615324575b66080000000000008316615312575b66040000000000008316615300575b660200000000000083166152ee575b6601000000000000831615614c8e5768010000b17255775c0402831c614c8e565b6801000162e525ee054702831c6152cd565b68010002c5cc37da949202831c6152be565b680100058ba01fb9f96d02831c6152af565b6801000b175effdc76ba02831c6152a0565b680100162f3904051fa102831c615291565b6801002c605e2e8cec5002831c615282565b68010058c86da1c09ea202831c615273565b678000000000000000831661546a575b6740000000000000008316615458575b6720000000000000008316615446575b6710000000000000008316615434575b6708000000000000008316615422575b6704000000000000008316615410575b67020000000000000083166153fe575b670100000000000000831615614c7f57680100b1afa5abcbed6102831c614c7f565b68010163da9fb33356d802831c6153dc565b680102c9a3e778060ee702831c6153cc565b6801059b0d31585743ae02831c6153bc565b68010b5586cf9890f62a02831c6153ac565b6801172b83c7d517adce02831c61539c565b6801306fe0a31b7152df02831c61538c565b5077b504f333f9de64848000000000000000000000000000000061537c565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461555857670de0b6b3a7640000908183101561552157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155a8575080511561557e57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155f3575b6155b9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155b156fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962005a3b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156399081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab826141c7565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141c7565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b657610713846141c7565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614605565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161465f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d8588614605565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614197565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a6141c7565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be916141ef565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b87825285522001541694613151818988614605565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e6134378361465f565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b916141ef565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c88614605565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a8906142db565b90565b6137a89061420a565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b0360408401511660206101008501510151906144bb565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b038351169030903390614594565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b036101008601515116903390614594565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b515116906141ef565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b3d156141c2573d906141a8826129b2565b916141b66040519384612990565b82523d6000602084013e565b606090565b6137a8906141d48161465f565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff61423f600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146da565b91808252600a602052604082208054156142c75790829167ffffffffffffffff9352614299602083205482845260096020526142946001600160801b03968760026040882001541696879360801c16906147ca565b614838565b9283136142af5750506142ab90614922565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161430183612973565b80549661012061438760026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a60205261439e858520612df7565b91849680876143ac866139f8565b5101511692828288955b161061448557509161443a6142949284888161443f98976001600160801b039e8f6143e1898c613a05565b5151169d8e9a67ffffffffffffffff60206143fc8c84613a05565b5101511699848361440d8385613a05565b5101511696508015614479576144299293506000190190613a05565b5101511680925b03169203166146da565b6147ca565b9283136144585750506144528391614922565b16011690565b5160200151929392831692841683101591506144749050575090565b905090565b50505051168092614430565b8093986001600160801b03908161449c8c89613a05565b51511601169801928282808a6144b2888a613a05565b510151166143b6565b919091604051906144cb82612943565b600091828152826020820152936001600160801b03928383169182156145755767016345785d8a000080821161453e57506145078591846154ea565b166020870192818452111561452a5750908261452592511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061458982612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb576146039260405261495e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146039161465a606483612990565b61495e565b8060005260096020526146786002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146146ab57506001600160801b039150602001511690565b5460f81c6146bd57506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b600160ff1b8082149081156147c0575b5061479657600081121561478d57614713816000035b60008412156147865783600003906149fa565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474f57600019911813156147495790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fa565b61471381614700565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ea565b806147e557506147e057670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483257508061480a575050670de0b6b3a764000090565b670de0b6b3a7640000811461482e57614829906142946137a893614af4565b614c36565b5090565b91505090565b600160ff1b808214908115614918575b506148ee5760008112156148e557614871816000035b60008412156148de5783600003906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a757600019911813156147495790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ea565b6148718161485e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614848565b6000811261492d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614989600080836020829551910182875af1614982614197565b9084615599565b9081519182151592836149d2575b5050506149a15750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614997565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab65782851015614a7a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac4570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac4576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0557670de0b6b3a764000092838112614be257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd657506706f05b59d3b20000905b848213614baa5750505050500290565b808391020590671bc16d674ec80000821215614bc9575b831d90614b9a565b8091950194831d90614bc1565b93505093925050020290565b6000199392508015614ac4576ec097ce7bc90715b34b9f10000000000591614b15565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c655768033dd1780914b9711419811261384a57614c5c90600003614c36565b6137a890614ada565b680a688906bd8affffff81136154b957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539c575b66ff0000000000008316615294575b65ff00000000008316615194575b64ff00000000831661509c575b63ff0000008316614fac575b62ff00008316614ec4575b61ff008316614de4575b60ff8316614d0d575b02911c60bf031c90565b60808316614dd2575b838316614dc0575b60208316614dae575b60108316614d9c575b60088316614d8a575b60048316614d78575b60028316614d66575b6001831615614d03576801000000000000000102831c614d03565b6801000000000000000102831c614d4b565b6801000000000000000302831c614d42565b6801000000000000000602831c614d39565b6801000000000000000b02831c614d30565b6801000000000000001602831c614d27565b6801000000000000002c02831c614d1e565b6801000000000000005902831c614d16565b6180008316614eb2575b6140008316614ea0575b6120008316614e8e575b6110008316614e7c575b6108008316614e6a575b6104008316614e58575b6102008316614e46575b610100831615614cfa57680100000000000000b102831c614cfa565b6801000000000000016302831c614e2a565b680100000000000002c602831c614e20565b6801000000000000058c02831c614e16565b68010000000000000b1702831c614e0c565b6801000000000000162e02831c614e02565b68010000000000002c5d02831c614df8565b680100000000000058b902831c614dee565b628000008316614f9a575b624000008316614f88575b622000008316614f76575b621000008316614f64575b620800008316614f52575b620400008316614f40575b620200008316614f2e575b62010000831615614cf0576801000000000000b17202831c614cf0565b680100000000000162e402831c614f11565b6801000000000002c5c802831c614f06565b68010000000000058b9102831c614efb565b680100000000000b172102831c614ef0565b68010000000000162e4302831c614ee5565b680100000000002c5c8602831c614eda565b6801000000000058b90c02831c614ecf565b6380000000831661508a575b63400000008316615078575b63200000008316615066575b63100000008316615054575b63080000008316615042575b63040000008316615030575b6302000000831661501e575b6301000000831615614ce55768010000000000b1721802831c614ce5565b6801000000000162e43002831c615000565b68010000000002c5c86002831c614ff4565b680100000000058b90c002831c614fe8565b6801000000000b17217f02831c614fdc565b680100000000162e42ff02831c614fd0565b6801000000002c5c85fe02831c614fc4565b68010000000058b90bfc02831c614fb8565b6480000000008316615182575b6440000000008316615170575b642000000000831661515e575b641000000000831661514c575b640800000000831661513a575b6404000000008316615128575b6402000000008316615116575b640100000000831615614cd957680100000000b17217f802831c614cd9565b68010000000162e42ff102831c6150f7565b680100000002c5c85fe302831c6150ea565b6801000000058b90bfce02831c6150dd565b68010000000b17217fbb02831c6150d0565b6801000000162e42fff002831c6150c3565b68010000002c5c8601cc02831c6150b6565b680100000058b90c0b4902831c6150a9565b658000000000008316615282575b654000000000008316615270575b65200000000000831661525e575b65100000000000831661524c575b65080000000000831661523a575b650400000000008316615228575b650200000000008316615216575b65010000000000831615614ccc576801000000b17218355102831c614ccc565b680100000162e430e5a202831c6151f6565b6801000002c5c863b73f02831c6151e8565b68010000058b90cf1e6e02831c6151da565b680100000b1721bcfc9a02831c6151cc565b68010000162e43f4f83102831c6151be565b680100002c5c89d5ec6d02831c6151b0565b6801000058b91b5bc9ae02831c6151a2565b6680000000000000831661538a575b66400000000000008316615378575b66200000000000008316615366575b66100000000000008316615354575b66080000000000008316615342575b66040000000000008316615330575b6602000000000000831661531e575b6601000000000000831615614cbe5768010000b17255775c0402831c614cbe565b6801000162e525ee054702831c6152fd565b68010002c5cc37da949202831c6152ee565b680100058ba01fb9f96d02831c6152df565b6801000b175effdc76ba02831c6152d0565b680100162f3904051fa102831c6152c1565b6801002c605e2e8cec5002831c6152b2565b68010058c86da1c09ea202831c6152a3565b678000000000000000831661549a575b6740000000000000008316615488575b6720000000000000008316615476575b6710000000000000008316615464575b6708000000000000008316615452575b6704000000000000008316615440575b670200000000000000831661542e575b670100000000000000831615614caf57680100b1afa5abcbed6102831c614caf565b68010163da9fb33356d802831c61540c565b680102c9a3e778060ee702831c6153fc565b6801059b0d31585743ae02831c6153ec565b68010b5586cf9890f62a02831c6153dc565b6801172b83c7d517adce02831c6153cc565b6801306fe0a31b7152df02831c6153bc565b5077b504f333f9de6484800000000000000000000000000000006153ac565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558857670de0b6b3a7640000908183101561555157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d857508051156155ae57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615623575b6155e9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e156fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f620049a33881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c69081620003dd8239608051816139480152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5f57508063027b674414612f3c57806306fdde0314612e77578063081812fc14612e58578063095ea7b314612d5f5780631400ecec14612cbf5780631c1cdd4c14612c5a5780631e99d56914612c3c57806323b872dd14612c2457806340e58ee5146129a6578063425d30dd1461295557806342842e0e1461290557806342966c681461272a57806344267570146127035780634857501f1461268d5780634869e12d146126525780634cc55e11146121c257806353b15727146120a35780636352211e146120735780636d0cee751461207357806370a082311461200357806375829def14611f70578063780a82c814611f235780637cad6cd114611e295780637de6b1db14611c025780638659c270146118b1578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f61308e565b916102786131eb565b9261028161393e565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140b1565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134e2565b906103b181868401511692826040818351169201511690613225565b161115610532575b848c528252600160408c20015416946103d3818a886140dc565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b6104919061310a565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b6105199061310a565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d58961399a565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576004359061074761308e565b91610278816140b1565b503461064c57604036600319011261064c5761076b613078565b604061077561308e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140b1565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134c3565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b8561313b565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613697565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e6604051928284938452830190613053565b0390f35b909192503d8082843e6109fd81846131ad565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131cf565b93610a4160405195866131ad565b83855285848401011161064c575090610a5f91848085019101613030565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a9461308e565b610a9c61393e565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140b1565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f9565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b61393e565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140b1565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613225565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140dc565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c9061310a565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e009061310a565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a61399a565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613078565b61101a61308e565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131cf565b9361105760405195866131ad565b8585523660248783010111610a6757856110829660246020930183880137850101526044359161352a565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f90613772565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c5761115361393e565b61115b6134c3565b9064ffffffffff80421680845281611171613516565b1615611280578180611181613516565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b57604051976112118961311e565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613191565b61010435918216820361127b57826112739260209452610124358482015260e0820152613a03565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613078565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f7925003836131ad565b6109e6604051928284938452830190613053565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e90613772565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101606040516115b381613157565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f66134c3565b61014082015201526004358152600960205260ff600160408320015460a81c1615611899576004358152600960205260408120906116c460026040519361163c85613174565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134e2565b6101208301526116d5600435613772565b6005811015611885576101606101c093600264ffffffffff931461187a575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117818d613157565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f4565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118e49036906004016130d9565b91906118ee61393e565b83925b8084106118fc578480f35b61190784828461349d565b359361191161393e565b848652600980855260ff90600190828260408b20015460a81c1615611beb57878952808752604089208281015460a01c8416156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd3576119918160005260096020526001600160a01b0360406000205416331490565b15611bb35761199f816136ba565b818a528289526119b4600260408c20016134e2565b906001600160801b0395868351168783161015611b9b57838c52848b5260408c205460f01c1615611b835791818a611a0585898f9a9998966119fb8c998387935116613225565b9501511690613225565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b6a575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaf8b85886140dc565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b13575b5050505050506001019291906118f1565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b56575b80808080611b02565b611b5f9061310a565b610524578438611b4d565b818601600160a01b60ff60a01b19825416179055611a6a565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c2161393e565b8183526009815260ff600160408520015460a81c1615611e1257611c4482613772565b6005811015611dfe5760048103611c6d5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8d576024836040519063fe19f19f60e01b82526004820152fd5b600214611de657611cb48260005260096020526001600160a01b0360406000205416331490565b15611dc7578183526009815260ff604084205460f01c1615611daf57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d57575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9b575b80611d28565b611da49061310a565b61049c578238611d95565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611efa575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f8a613078565b9080546001600160a01b0380821693338503611fdc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612025613078565b168015612042578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c576020612092600435613697565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120be61393e565b604051906120cb8261311e565b6120d3613078565b82526120dd61308e565b60208301526120ea6131eb565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c57506040516121448161313b565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161219a83613191565b61012435918216820361127b57826112739260209452610144358482015260e0820152613a03565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f59036906004016130d9565b90916024359081116104a05761220f9036906004016130d9565b61221761393e565b80830361261b57845b83811061222b578580f35b61223681858761349d565b359061224381868861349d565b35875260036020526001600160a01b0360408820541661226482858761349d565b35906001600160801b038216820361127b5761227e61393e565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156126035783895260036020526001600160a01b0360408a2054169182821415806125f3575b6125cf576122f6856140b1565b6001600160801b0381166001600160801b0383161161259f5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123878c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ab8160208401511692826040818351169201511690613225565b16111561256e575b86855260096020526001600160a01b036001604087200154166123e06001600160801b03841685836140dc565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612564575b6124fa575b8333141590816124ef575b816124e4575b50612472575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612220565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124cc575b808061243b565b6124d59061310a565b6124e05786386124c5565b8680fd5b905083141538612435565b843b1515915061242f565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612550575b5050612424565b6125599061310a565b610524578438612549565b50803b151561241f565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b3565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125fd8561399a565b156122e9565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614138565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257806126c883613772565b926005841015611885576002602094036126e9575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126dd565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a67576004359061274961393e565b8183526009815260ff600160408520015460a81c1615611e12578183526009815260ff600160408520015460a01c16156128d4576127868261399a565b15611dc75781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128ca575b50806128c2575b6128aa577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286f575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612857575080f35b60249060405190637e27328960e01b82526004820152fd5b61289085600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612805565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c5565b90501515386127be565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57612914366130a4565b60405191602083019383851067ffffffffffffffff86111761293f576110829460405285845261352a565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c661393e565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a145760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bd357612a3f8160005260096020526001600160a01b0360406000205416331490565b15611bb357612a4d816136ba565b93818452808352612a63600260408620016134e2565b916001600160801b0393848451168588161015611de65781865282815260ff604087205460f01c1615611daf57612ab1878683612aa78a9b838a9c9b9c5116613225565b9701511690613225565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c0a575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b3d8c84876140dc565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb9578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bfb575b81818080808480f35b612c049061310a565b81612bf2565b60018101600160a01b60ff60a01b19825416179055612af6565b503461064c57611082612c36366130a4565b91613254565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c9390613772565b90600582101561156f5760208215838115612cb4575b506040519015158152f35b600191501482612ca9565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257602091604082828152600985522060ff815460f01c1680612d4d575b612d24575b50506001600160801b0360405191168152f35b612d4692506001600160801b036002612d4092015416916136ba565b90613225565b3880612d11565b5060ff600182015460a01c1615612d0c565b503461064c57604036600319011261064c57612d79613078565b602435612d8581613697565b33151580612e45575b80612e1b575b612deb5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d94565b50336001600160a01b0382161415612d8e565b503461064c57602036600319011261064c576020612092600435613201565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f32575b602095868610811461148757858852879493929187908215611465575050600114612ed85750506113f7925003836131ad565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f1a5750506113f7935082010138806113e9565b80548389018501528794508693909201918101612f02565b93607f1693612ea5565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613006575b8115612fdc575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fce565b60005b8381106130435750506000910152565b8181015183820152602001613033565b9060209161306c81518092818552858086019101613030565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161293f57604052565b610100810190811067ffffffffffffffff82111761293f57604052565b6060810190811067ffffffffffffffff82111761293f57604052565b610180810190811067ffffffffffffffff82111761293f57604052565b610140810190811067ffffffffffffffff82111761293f57604052565b6040810190811067ffffffffffffffff82111761293f57604052565b90601f8019910116810190811067ffffffffffffffff82111761293f57604052565b67ffffffffffffffff811161293f57601f01601f191660200190565b604435906001600160801b038216820361127b57565b61320a81613697565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323e57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161347b575b5080613473575b61345c5786855260038152828486205416948733151593846133ac575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613374575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133465750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339582600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132e2565b9192938091509061341b575b156133c657908783926132b9565b8488876133e3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613440575b806133b857508782526005835233848684205416146133b8565b5085825260068352848220338352835260ff8583205416613426565b602487855190630da9b01360e01b82526004820152fd5b50600161329c565b9050151538613295565b6024604051633250574960e11b815260006004820152fd5b91908110156134ad5760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134d08261313b565b60006040838281528260208201520152565b906040516134ef8161313b565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b9190613537828285613254565b803b613544575b50505050565b6135a06001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613053565b03906020816000938185885af190829082613636575b50506135ed57826135c5614081565b80519190826135e65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361361e57503880808061353e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368f575b81613653602093836131ad565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b6565b3d9150613646565b8060005260036020526001600160a01b0360406000205416908115612857575090565b600090808252600a60205264ffffffffff9182604082205416421061376c5760096020526040812092835490808260c81c1691824210156137565761370b9394955060a01c168091039042036142fb565b9082815260096020526001600160801b03926137318460026040852001541680946143db565b92831161373e5750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613799575050600490565b805460f81c6137f2575460a01c64ffffffffff1642106137ec576137bc816136ba565b9060005260096020526001600160801b0380600260406000200154169116106000146137e757600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613934575b5080613929575b613912579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138da575b1692836138c4575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a0565b6138fb86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613898565b602486885190630da9b01360e01b82526004820152fd5b508181161515613837565b9050151538613830565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361397057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139df575b505082156139cd57505090565b9091506139da3392613201565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139c0565b90613a246001600160801b03604084015116602060e08501510151906141b3565b916001600160801b0383511660c082015190156140575764ffffffffff8151161561402d5764ffffffffff81511690604081019164ffffffffff8351169081811015613fed575050602081019064ffffffffff8251169081151580613fdb575b613f9a57505064ffffffffff90511664ffffffffff8251169081811015613f5a57505064ffffffffff8042169151169081811015613f1a575050600754926001600160801b0381511660405190613ada8261313b565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b3c88613174565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d3484875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613efc575b50600184016007556001600160a01b03602083015116801561348557613d84856001600160a01b03926137f9565b16613ecb57613daf6001600160a01b036060840151166001600160801b03835116903090339061428c565b6001600160801b0360208201511680613e9c575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e936001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec5906001600160a01b036060850151166001600160a01b0360e0860151511690339061428c565b38613dc3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d56565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a84565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517f62201b50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140ac573d90614092826131cf565b916140a060405193846131ad565b82523d6000602084013e565b606090565b6140d9906140be81614138565b90600052600960205260026040600020015460801c90613225565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152614136916141316064836131ad565b61448a565b565b80600052600960205261415160026040600020016134e2565b816000526009602052604060002060ff600182015460a01c1660001461418457506001600160801b039150602001511690565b5460f81c61419657506140d9906136ba565b6140d991506001600160801b036040818351169201511690613225565b919091604051906141c382613191565b600091828152826020820152936001600160801b039283831691821561426d5767016345785d8a000080821161423657506141ff8591846143db565b16602087019281845211156142225750908261421d92511690613225565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061428182613191565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293f576141369260405261448a565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b7578285101561437b57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c5570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447957670de0b6b3a7640000908183101561444257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b5600080836020829551910182875af16144ae614081565b9084614526565b9081519182151592836144fe575b5050506144cd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144c3565b90614565575080511561453b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145b0575b614576575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456e56fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f620049a33881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c69081620003dd8239608051816139480152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5f57508063027b674414612f3c57806306fdde0314612e77578063081812fc14612e58578063095ea7b314612d5f5780631400ecec14612cbf5780631c1cdd4c14612c5a5780631e99d56914612c3c57806323b872dd14612c2457806340e58ee5146129a6578063425d30dd1461295557806342842e0e1461290557806342966c681461272a57806344267570146127035780634857501f1461268d5780634869e12d146126525780634cc55e11146121c257806353b15727146120a35780636352211e146120735780636d0cee751461207357806370a082311461200357806375829def14611f70578063780a82c814611f235780637cad6cd114611e295780637de6b1db14611c025780638659c270146118b1578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f61308e565b916102786131eb565b9261028161393e565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140b1565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134e2565b906103b181868401511692826040818351169201511690613225565b161115610532575b848c528252600160408c20015416946103d3818a886140dc565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b6104919061310a565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b6105199061310a565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d58961399a565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576004359061074761308e565b91610278816140b1565b503461064c57604036600319011261064c5761076b613078565b604061077561308e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140b1565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134c3565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b8561313b565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613697565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e6604051928284938452830190613053565b0390f35b909192503d8082843e6109fd81846131ad565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131cf565b93610a4160405195866131ad565b83855285848401011161064c575090610a5f91848085019101613030565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a9461308e565b610a9c61393e565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140b1565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f9565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b61393e565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140b1565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613225565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140dc565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c9061310a565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e009061310a565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a61399a565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613078565b61101a61308e565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131cf565b9361105760405195866131ad565b8585523660248783010111610a6757856110829660246020930183880137850101526044359161352a565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f90613772565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c5761115361393e565b61115b6134c3565b9064ffffffffff80421680845281611171613516565b1615611280578180611181613516565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b57604051976112118961311e565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613191565b61010435918216820361127b57826112739260209452610124358482015260e0820152613a03565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613078565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f7925003836131ad565b6109e6604051928284938452830190613053565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e90613772565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101606040516115b381613157565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f66134c3565b61014082015201526004358152600960205260ff600160408320015460a81c1615611899576004358152600960205260408120906116c460026040519361163c85613174565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134e2565b6101208301526116d5600435613772565b6005811015611885576101606101c093600264ffffffffff931461187a575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117818d613157565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f4565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118e49036906004016130d9565b91906118ee61393e565b83925b8084106118fc578480f35b61190784828461349d565b359361191161393e565b848652600980855260ff90600190828260408b20015460a81c1615611beb57878952808752604089208281015460a01c8416156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd3576119918160005260096020526001600160a01b0360406000205416331490565b15611bb35761199f816136ba565b818a528289526119b4600260408c20016134e2565b906001600160801b0395868351168783161015611b9b57838c52848b5260408c205460f01c1615611b835791818a611a0585898f9a9998966119fb8c998387935116613225565b9501511690613225565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b6a575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaf8b85886140dc565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b13575b5050505050506001019291906118f1565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b56575b80808080611b02565b611b5f9061310a565b610524578438611b4d565b818601600160a01b60ff60a01b19825416179055611a6a565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c2161393e565b8183526009815260ff600160408520015460a81c1615611e1257611c4482613772565b6005811015611dfe5760048103611c6d5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8d576024836040519063fe19f19f60e01b82526004820152fd5b600214611de657611cb48260005260096020526001600160a01b0360406000205416331490565b15611dc7578183526009815260ff604084205460f01c1615611daf57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d57575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9b575b80611d28565b611da49061310a565b61049c578238611d95565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611efa575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f8a613078565b9080546001600160a01b0380821693338503611fdc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612025613078565b168015612042578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c576020612092600435613697565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120be61393e565b604051906120cb8261311e565b6120d3613078565b82526120dd61308e565b60208301526120ea6131eb565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c57506040516121448161313b565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161219a83613191565b61012435918216820361127b57826112739260209452610144358482015260e0820152613a03565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f59036906004016130d9565b90916024359081116104a05761220f9036906004016130d9565b61221761393e565b80830361261b57845b83811061222b578580f35b61223681858761349d565b359061224381868861349d565b35875260036020526001600160a01b0360408820541661226482858761349d565b35906001600160801b038216820361127b5761227e61393e565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156126035783895260036020526001600160a01b0360408a2054169182821415806125f3575b6125cf576122f6856140b1565b6001600160801b0381166001600160801b0383161161259f5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123878c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ab8160208401511692826040818351169201511690613225565b16111561256e575b86855260096020526001600160a01b036001604087200154166123e06001600160801b03841685836140dc565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612564575b6124fa575b8333141590816124ef575b816124e4575b50612472575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612220565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124cc575b808061243b565b6124d59061310a565b6124e05786386124c5565b8680fd5b905083141538612435565b843b1515915061242f565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612550575b5050612424565b6125599061310a565b610524578438612549565b50803b151561241f565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b3565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125fd8561399a565b156122e9565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614138565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257806126c883613772565b926005841015611885576002602094036126e9575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126dd565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a67576004359061274961393e565b8183526009815260ff600160408520015460a81c1615611e12578183526009815260ff600160408520015460a01c16156128d4576127868261399a565b15611dc75781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128ca575b50806128c2575b6128aa577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286f575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612857575080f35b60249060405190637e27328960e01b82526004820152fd5b61289085600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612805565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c5565b90501515386127be565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57612914366130a4565b60405191602083019383851067ffffffffffffffff86111761293f576110829460405285845261352a565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c661393e565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a145760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bd357612a3f8160005260096020526001600160a01b0360406000205416331490565b15611bb357612a4d816136ba565b93818452808352612a63600260408620016134e2565b916001600160801b0393848451168588161015611de65781865282815260ff604087205460f01c1615611daf57612ab1878683612aa78a9b838a9c9b9c5116613225565b9701511690613225565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c0a575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b3d8c84876140dc565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb9578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bfb575b81818080808480f35b612c049061310a565b81612bf2565b60018101600160a01b60ff60a01b19825416179055612af6565b503461064c57611082612c36366130a4565b91613254565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c9390613772565b90600582101561156f5760208215838115612cb4575b506040519015158152f35b600191501482612ca9565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257602091604082828152600985522060ff815460f01c1680612d4d575b612d24575b50506001600160801b0360405191168152f35b612d4692506001600160801b036002612d4092015416916136ba565b90613225565b3880612d11565b5060ff600182015460a01c1615612d0c565b503461064c57604036600319011261064c57612d79613078565b602435612d8581613697565b33151580612e45575b80612e1b575b612deb5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d94565b50336001600160a01b0382161415612d8e565b503461064c57602036600319011261064c576020612092600435613201565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f32575b602095868610811461148757858852879493929187908215611465575050600114612ed85750506113f7925003836131ad565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f1a5750506113f7935082010138806113e9565b80548389018501528794508693909201918101612f02565b93607f1693612ea5565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613006575b8115612fdc575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fce565b60005b8381106130435750506000910152565b8181015183820152602001613033565b9060209161306c81518092818552858086019101613030565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161293f57604052565b610100810190811067ffffffffffffffff82111761293f57604052565b6060810190811067ffffffffffffffff82111761293f57604052565b610180810190811067ffffffffffffffff82111761293f57604052565b610140810190811067ffffffffffffffff82111761293f57604052565b6040810190811067ffffffffffffffff82111761293f57604052565b90601f8019910116810190811067ffffffffffffffff82111761293f57604052565b67ffffffffffffffff811161293f57601f01601f191660200190565b604435906001600160801b038216820361127b57565b61320a81613697565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323e57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161347b575b5080613473575b61345c5786855260038152828486205416948733151593846133ac575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613374575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133465750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339582600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132e2565b9192938091509061341b575b156133c657908783926132b9565b8488876133e3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613440575b806133b857508782526005835233848684205416146133b8565b5085825260068352848220338352835260ff8583205416613426565b602487855190630da9b01360e01b82526004820152fd5b50600161329c565b9050151538613295565b6024604051633250574960e11b815260006004820152fd5b91908110156134ad5760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134d08261313b565b60006040838281528260208201520152565b906040516134ef8161313b565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b9190613537828285613254565b803b613544575b50505050565b6135a06001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613053565b03906020816000938185885af190829082613636575b50506135ed57826135c5614081565b80519190826135e65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361361e57503880808061353e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368f575b81613653602093836131ad565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b6565b3d9150613646565b8060005260036020526001600160a01b0360406000205416908115612857575090565b600090808252600a60205264ffffffffff9182604082205416421061376c5760096020526040812092835490808260c81c1691824210156137565761370b9394955060a01c168091039042036142fb565b9082815260096020526001600160801b03926137318460026040852001541680946143db565b92831161373e5750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613799575050600490565b805460f81c6137f2575460a01c64ffffffffff1642106137ec576137bc816136ba565b9060005260096020526001600160801b0380600260406000200154169116106000146137e757600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613934575b5080613929575b613912579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138da575b1692836138c4575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a0565b6138fb86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613898565b602486885190630da9b01360e01b82526004820152fd5b508181161515613837565b9050151538613830565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361397057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139df575b505082156139cd57505090565b9091506139da3392613201565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139c0565b90613a246001600160801b03604084015116602060e08501510151906141b3565b916001600160801b0383511660c082015190156140575764ffffffffff8151161561402d5764ffffffffff81511690604081019164ffffffffff8351169081811015613fed575050602081019064ffffffffff8251169081151580613fdb575b613f9a57505064ffffffffff90511664ffffffffff8251169081811015613f5a57505064ffffffffff8042169151169081811015613f1a575050600754926001600160801b0381511660405190613ada8261313b565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b3c88613174565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d3484875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613efc575b50600184016007556001600160a01b03602083015116801561348557613d84856001600160a01b03926137f9565b16613ecb57613daf6001600160a01b036060840151166001600160801b03835116903090339061428c565b6001600160801b0360208201511680613e9c575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e936001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec5906001600160a01b036060850151166001600160a01b0360e0860151511690339061428c565b38613dc3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d56565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a84565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140ac573d90614092826131cf565b916140a060405193846131ad565b82523d6000602084013e565b606090565b6140d9906140be81614138565b90600052600960205260026040600020015460801c90613225565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152614136916141316064836131ad565b61448a565b565b80600052600960205261415160026040600020016134e2565b816000526009602052604060002060ff600182015460a01c1660001461418457506001600160801b039150602001511690565b5460f81c61419657506140d9906136ba565b6140d991506001600160801b036040818351169201511690613225565b919091604051906141c382613191565b600091828152826020820152936001600160801b039283831691821561426d5767016345785d8a000080821161423657506141ff8591846143db565b16602087019281845211156142225750908261421d92511690613225565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061428182613191565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293f576141369260405261448a565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b7578285101561437b57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c5570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447957670de0b6b3a7640000908183101561444257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b5600080836020829551910182875af16144ae614081565b9084614526565b9081519182151592836144fe575b5050506144cd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144c3565b90614565575080511561453b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145b0575b614576575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456e56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004dcf3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149cd908162000402823960805181613dda015260a051818181612eb80152613e7a0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613dd0565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961457d565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610343916145a8565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a8861470d565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8896144e4565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b916107498161457d565b92610752613dd0565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961457d565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b85761089360209161457d565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613dd0565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b628661457d565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c8b565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613dd0565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a61457d565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c6145a8565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d3381868861470d565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a6144e4565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613c04565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613c04565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613dd0565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613e2c565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613c04565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613dd0565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613dd0565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b858861470d565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613dd0565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613c04565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613dd0565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613dd0565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b8561457d565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c6145a8565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b038416858361470d565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b50612717856144e4565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614767565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613c04565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613dd0565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a0826144e4565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613dd0565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c848761470d565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613dd0565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613c04565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc61454d565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613b166040822061386e565b9185856020613b2486613ad1565b5101511611613bfb5781526009602052604081208585825460c81c161115613be557506001600160801b039485613b5a84613ad1565b5151169583519260019360011015613bd15750949392919084602060408501510151169581866001985b161115613b95575050505050505090565b909181879881613ba98798999a8598613ade565b5151160116970191868087613bbe8689613ade565b5101511697829392919796959498613b84565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613c2b575050600490565b805460f81c613c84575460a01c64ffffffffff164210613c7e57613c4e81613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c7957600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613dc6575b5080613dbb575b613da4579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d6c575b169283613d56575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d32565b613d8d86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d2a565b602486885190630da9b01360e01b82526004820152fd5b508181161515613cc9565b9050151538613cc2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e0257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e4e6001600160801b0360408401511660206101008501510151906145c3565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144ba5781518015614490577f0000000000000000000000000000000000000000000000000000000000000000811161445f575064ffffffffff6020613eb184613ad1565b510151168110156144085750600090819082815184905b808210614377575050505064ffffffffff421664ffffffffff82168110156143375750506001600160801b0316808203614300575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140648951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b81811061425b575050600185016007556001600160a01b03602083015116801561378d576140b1866001600160a01b0392613c8b565b1661422a576140dc6001600160a01b036060840151166001600160801b03835116903090339061469c565b6001600160801b03602082015116806141fa575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141ef6141d060808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141798c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b614224906001600160a01b036060850151166001600160a01b03610100860151511690339061469c565b386140f0565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142788160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b169216171790550161407b565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b919350919361439b906001600160801b036143928588613ade565b515116906145a8565b9364ffffffffff8060206143af8685613ade565b510151169416808511156143cb57506001849301909291613ec8565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061441984613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614529575b5050821561451757505090565b9091506145243392613509565b161490565b60ff929450906040918152600660205281812033825260205220541691388061450a565b3d15614578573d9061455e826134d9565b9161456c60405193846134b7565b82523d6000602084013e565b606090565b6145a59061458a81614767565b90600052600960205260026040600020015460801c9061352d565b90565b9190916001600160801b038080941691160191821161354657565b919091604051906145d38261349b565b600091828152826020820152936001600160801b039283831691821561467d5767016345785d8a0000808211614646575061460f85918461487e565b16602087019281845211156146325750908261462d9251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146918261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761470b926040526147e2565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261470b916147626064836134b7565b6147e2565b80600052600960205261478060026040600020016138ec565b816000526009602052604060002060ff600182015460a01c166000146147b357506001600160801b039150602001511690565b5460f81c6147c557506145a590613af2565b6145a591506001600160801b03604081835116920151169061352d565b6001600160a01b03169061480d600080836020829551910182875af161480661454d565b908461492d565b908151918215159283614856575b5050506148255750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061481b565b9091906000198382098382029182808310920391808303921461491c57670de0b6b3a764000090818310156148e557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061496c575080511561494257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149b7575b61497d575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561497556fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004dff3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149fd908162000402823960805181613dda015260a051818181612eb80152613e800152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613dd0565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f896145ad565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610343916145d8565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a8861473d565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614514565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b91610749816145ad565b92610752613dd0565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f896145ad565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b8576108936020916145ad565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613dd0565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b62866145ad565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c8b565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613dd0565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a6145ad565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c6145d8565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d3381868861473d565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a614514565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613c04565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613c04565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613dd0565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613e2c565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613c04565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613dd0565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613dd0565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b858861473d565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613dd0565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613c04565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613dd0565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613dd0565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b856145ad565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c6145d8565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b038416858361473d565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061271785614514565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614797565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613c04565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613dd0565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a082614514565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613dd0565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c848761473d565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613dd0565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613c04565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc61457d565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613b166040822061386e565b9185856020613b2486613ad1565b5101511611613bfb5781526009602052604081208585825460c81c161115613be557506001600160801b039485613b5a84613ad1565b5151169583519260019360011015613bd15750949392919084602060408501510151169581866001985b161115613b95575050505050505090565b909181879881613ba98798999a8598613ade565b5151160116970191868087613bbe8689613ade565b5101511697829392919796959498613b84565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613c2b575050600490565b805460f81c613c84575460a01c64ffffffffff164210613c7e57613c4e81613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c7957600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613dc6575b5080613dbb575b613da4579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d6c575b169283613d56575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d32565b613d8d86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d2a565b602486885190630da9b01360e01b82526004820152fd5b508181161515613cc9565b9050151538613cc2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e0257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e4e6001600160801b0360408401511660206101008501510151906145f3565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144ea5780156144c05781518015614496577f00000000000000000000000000000000000000000000000000000000000000008111614465575064ffffffffff6020613eb784613ad1565b5101511681101561440e5750600090819082815184905b80821061437d575050505064ffffffffff421664ffffffffff821681101561433d5750506001600160801b0316808203614306575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406a8951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b818110614261575050600185016007556001600160a01b03602083015116801561378d576140b7866001600160a01b0392613c8b565b16614230576140e26001600160a01b036060840151166001600160801b0383511690309033906146cc565b6001600160801b0360208201511680614200575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141f56141d660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a61417f8c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61422a906001600160a01b036060850151166001600160a01b0361010086015151169033906146cc565b386140f6565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a60205260406000209061427e8160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614081565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143a1906001600160801b036143988588613ade565b515116906145d8565b9364ffffffffff8060206143b58685613ade565b510151169416808511156143d157506001849301909291613ece565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061441f84613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614559575b5050821561454757505090565b9091506145543392613509565b161490565b60ff929450906040918152600660205281812033825260205220541691388061453a565b3d156145a8573d9061458e826134d9565b9161459c60405193846134b7565b82523d6000602084013e565b606090565b6145d5906145ba81614797565b90600052600960205260026040600020015460801c9061352d565b90565b9190916001600160801b038080941691160191821161354657565b919091604051906146038261349b565b600091828152826020820152936001600160801b03928383169182156146ad5767016345785d8a0000808211614676575061463f8591846148ae565b16602087019281845211156146625750908261465d9251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146c18261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761473b92604052614812565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261473b916147926064836134b7565b614812565b8060005260096020526147b060026040600020016138ec565b816000526009602052604060002060ff600182015460a01c166000146147e357506001600160801b039150602001511690565b5460f81c6147f557506145d590613af2565b6145d591506001600160801b03604081835116920151169061352d565b6001600160a01b03169061483d600080836020829551910182875af161483661457d565b908461495d565b908151918215159283614886575b5050506148555750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061484b565b9091906000198382098382029182808310920391808303921461494c57670de0b6b3a7640000908183101561491557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061499c575080511561497257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149e7575b6149ad575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149a556fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615f2090816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661570a565b91601e604660ff61030b8460146050848d60081c1606011661570a565b981606011661570a565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615091565b16906151fa565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff8091169116615545565b610120516101805190929161059d602161053a6064610533818706615a17565b950461570a565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615b23565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b60008152866159eb565b156147c9576090945b6106fa8661570a565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b6109ec82615e9d565b808211156147c15750945b610a0287870161570a565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615e1f565b610d1b82615e9d565b808211156147b95750935b610d326028860161570a565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615190565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615aea565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615aea565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615aea565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615aea565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615190565b92611ce9611ce3614d0b565b896159eb565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615d63565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615d63565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615dcb565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615dcb565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461570a565b9461570a565b9761570a565b9161570a565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561570a565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561570a565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b610160516141049061585b565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e081905261585b565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b906159eb565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d84876159da565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa92831561508657600093615063575b50815192614eb6846149de565b60118452614eeb6020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159eb565b15614f295750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614f1f836149de565b600d835282015290565b614f668351614f37816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159eb565b15614fa45750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614f9a836149de565b600e835282015290565b614fe18351614fb2816149de565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159eb565b1561501f5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191615015836149de565b600f835282015290565b61505f9083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61507f91933d8091833e61507781836149fa565b810190614bce565b9138614ea9565b82513d6000823e3d90fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150c9816149de565b6000928392839251915afa6150dc614b9e565b9080615113575b1561510f5760208180518101031261510b57602001519060ff82168203615108575090565b80fd5b5080fd5b5090565b5060208151146150e3565b6040519061512b826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615164826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151f89294936040519586926020946151b281518092888089019101614909565b84016151c682518093888085019101614909565b016151d982518093878085019101614909565b016151ec82518093868085019101614909565b010380855201836149fa565b565b801561550a57600091806154e5575090505b600190808281101561527657505050615223615157565b614c2d602260405183615240829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c6800011156154885760409081519060a0820182811067ffffffffffffffff821117614402578084526152ad8161498a565b6000815282528251906152bf826149de565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152f9816149de565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615330816149de565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615368816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545c575b508451946153af866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615449575050505061542a615430917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615425866149de565b61570a565b91615a17565b916005851015614b6c57614c2d9460051b015192615190565b81810184015188820185015283016153e0565b9591926103e89081851061547f57508680916064600a870406950493019661539d565b939296506153a2565b505061549261511e565b614c2d6028604051836154af829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a9182156154f657500461520c565b80634e487b7160e01b602492526012600452fd5b5050604051615518816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155ad575061555a615157565b614c2d602660405183615577829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f811161567c576001810361563957614c2d60206156016040516155d2816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570a565b60405193816156198693518092868087019101614909565b820161562d82518093868085019101614909565b010380845201826149fa565b614c2d602061560160405161564d816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570a565b5061568561511e565b614c2d602a604051836156a2829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b906156e282614b82565b6156ef60405191826149fa565b8281528092615700601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561584d575b506d04ee2d6d415b85acef81000000008083101561583e575b50662386f26fc100008083101561582f575b506305f5e10080831015615820575b5061271080831015615811575b506064821015615801575b600a809210156157f7575b6001908160216157a2600187016156d8565b95860101905b6157b4575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f2579190826157a8565b6157ad565b9160010191615790565b9190606460029104910191615785565b6004919392049101913861577a565b6008919392049101913861576d565b6010919392049101913861575e565b6020919392049101913861574c565b604093508104915038615733565b8051156159c65760405161586e816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159b05760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159b05761590d906002959492951b6156d8565b936020850193839284518501935b84811061595d57505050505060039051068060011461594a5760021461593f575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061591b565b634e487b7160e01b600052601160045260246000fd5b506040516159d38161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615a01575050505090565b60209293945082012092012014388080806157ad565b80615a2957506040516159d38161498a565b600a811015615a8e57615a3b9061570a565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7e8151809260208686019101614909565b81010360028101845201826149fa565b615a979061570a565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ada8151809260208686019101614909565b81010360018101845201826149fa565b60405190615af7826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d5557615b31615aea565b906127109081039081116159b057614c2d91615b4f6101369261570a565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bdb815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c6382518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cc482518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159d38161498a565b60306151f8919392936040519481615d85879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dbc8251809360208785019101614909565b010360108101855201836149fa565b60256151f8919392936040519481615ded879351809260208087019101614909565b820164010714051160dd1b6020820152615e108251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e9557906000916000915b818310615e4457505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e7787856159da565b511614615e8d575b600d01936001019190615e32565b849350615e7f565b505050600090565b60009080518015615e9557906000916000915b818310615ec25750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ef587856159da565b511614615f0b575b601001936001019190615eb0565b849350615efd56fea164736f6c6343000817000a"; diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index d789e4692..39e8216a0 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -118,8 +118,8 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. + /// - `params.startTime` must be greater than zero and less than the first segment's timestamp /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`. - /// - `params.startTime` must be less than the first segment's timestamp. /// - The segment timestamps must be arranged in ascending order. /// - The last segment timestamp (i.e. the stream's end time) must be in the future. /// - The sum of the segment amounts must equal the deposit amount. diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index c13ba8638..645ef9f65 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -113,10 +113,8 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. - /// - `params.range.start` must be greater than zero. - /// - `params.range.start` must be less than `params.range.end`. - /// - If set, `params.range.cliff` must be greater than `params.range.start`. - /// - If set, `params.range.cliff` must be less than `params.range.end`. + /// - `params.range.start` must be greater than zero and less than `params.range.end`. + /// - If set, `params.range.cliff` must be greater than `params.range.start` and less than `params.range.end`. /// - `params.range.end` must be in the future. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index bdbd8a98e..64a7a89bd 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -115,8 +115,8 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. + /// - `params.startTime` must be greater than zero and less than the first tranche's timestamp /// - `params.tranches` must have at least one tranche, but not more than `MAX_TRANCHE_COUNT`. - /// - `params.startTime` must be less than the first tranche's timestamp. /// - The tranche timestamps must be arranged in ascending order. /// - The last tranche timestamp (i.e. the stream's end time) must be in the future. /// - The sum of the tranche amounts must equal the deposit amount. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index cf2b1b5e3..fc2554f35 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -39,6 +39,9 @@ library Errors { /// @notice Thrown when trying to withdraw an amount greater than the withdrawable amount. error SablierV2Lockup_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); + /// @notice Thrown when trying to create a stream with a zero start time. + error SablierV2Lockup_StartTimeZero(); + /// @notice Thrown when trying to cancel or renounce a canceled stream. error SablierV2Lockup_StreamCanceled(uint256 streamId); @@ -110,9 +113,6 @@ library Errors { /// @notice Thrown when trying to create a stream with a start time greater than the end time. error SablierV2LockupLinear_StartTimeNotLessThanEndTime(uint40 startTime, uint40 endTime); - /// @notice Thrown when trying to create a stream with a start time equal to zero. - error SablierV2LockupLinear_StartTimeZero(); - /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-NFT-DESCRIPTOR //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index b3823d3c7..ff64f4ffb 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -60,6 +60,11 @@ library Helpers { revert Errors.SablierV2Lockup_DepositAmountZero(); } + // Checks: the start time is not zero. + if (startTime == 0) { + revert Errors.SablierV2Lockup_StartTimeZero(); + } + // Checks: the segment count is not zero. uint256 segmentCount = segments.length; if (segmentCount == 0) { @@ -84,7 +89,7 @@ library Helpers { // Checks: the start time is not zero. if (range.start == 0) { - revert Errors.SablierV2LockupLinear_StartTimeZero(); + revert Errors.SablierV2Lockup_StartTimeZero(); } // Checks: the start time is strictly less than the end time. @@ -124,6 +129,11 @@ library Helpers { revert Errors.SablierV2Lockup_DepositAmountZero(); } + // Checks: the start time is not zero. + if (startTime == 0) { + revert Errors.SablierV2Lockup_StartTimeZero(); + } + // Checks: the tranche count is not zero. uint256 trancheCount = tranches.length; if (trancheCount == 0) { diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 3cb8057e4..4e5d66ff7 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -110,7 +110,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { checkUsers(params.sender, params.recipient, params.broker.account, address(lockupDynamic)); vm.assume(params.segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol index 114cbefb0..048411356 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/fork/LockupTranched.t.sol @@ -110,7 +110,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { checkUsers(params.sender, params.recipient, params.broker.account, address(lockupTranched)); vm.assume(params.tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); // Fuzz the tranche timestamps. fuzzTrancheTimestamps(params.tranches, params.startTime); diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 7ca13f5ae..effd678a9 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -48,11 +48,22 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithTotalAmount(totalAmount); } + function test_RevertWhen_StartTimeZero() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + { + vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); + createDefaultStreamWithStartTime(0); + } + function test_RevertWhen_SegmentCountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero { LockupDynamic.Segment[] memory segments; vm.expectRevert(Errors.SablierV2LockupDynamic_SegmentCountZero.selector); @@ -64,6 +75,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero { uint256 segmentCount = defaults.MAX_COUNT() + 1; @@ -79,6 +91,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh { @@ -94,6 +107,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -120,6 +134,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -146,6 +161,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -175,6 +191,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -192,6 +209,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -229,6 +247,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -249,6 +268,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -272,6 +292,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -290,6 +311,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index 34623142c..020277763 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -8,46 +8,49 @@ createWithTimestamps.t.sol ├── when the deposit amount is zero │ └── it should revert └── when the deposit amount is not zero - ├── when the segment count is zero + ├── when the start time is zero │ └── it should revert - └── when the segment count is not zero - ├── when the segment count is too high + └── when the start time is not zero + ├── when the segment count is zero │ └── it should revert - └── when the segment count is not too high - ├── when the segment amounts sum overflows + └── when the segment count is not zero + ├── when the segment count is too high │ └── it should revert - └── when the segment amounts sum does not overflow - ├── when the start time is greater than the first segment timestamp + └── when the segment count is not too high + ├── when the segment amounts sum overflows │ └── it should revert - ├── when the start time is equal to the first segment timestamp - │ └── it should revert - └── when the start time is less than the first segment timestamp - ├── when the segment timestamps are not ordered + └── when the segment amounts sum does not overflow + ├── when the start time is greater than the first segment timestamp + │ └── it should revert + ├── when the start time is equal to the first segment timestamp │ └── it should revert - └── when the segment timestamps are ordered - ├── when the end time is not in the future + └── when the start time is less than the first segment timestamp + ├── when the segment timestamps are not ordered │ └── it should revert - └── when the end time is in the future - ├── when the deposit amount is not equal to the segment amounts sum + └── when the segment timestamps are ordered + ├── when the end time is not in the future │ └── it should revert - └── when the deposit amount is equal to the segment amounts sum - ├── when the broker fee is too high + └── when the end time is in the future + ├── when the deposit amount is not equal to the segment amounts sum │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract + └── when the deposit amount is equal to the segment amounts sum + ├── when the broker fee is too high │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupDynamicStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupDynamicStream} event + └── when the broker fee is not too high + ├── when the asset is not a contract + │ └── it should revert + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupDynamicStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupDynamicStream} event diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 00dae75bb..4f90ab135 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -46,11 +46,16 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithTotalAmount(0); } - function test_RevertWhen_StartTimeZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { + function test_RevertWhen_StartTimeZero() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + { uint40 cliffTime = defaults.CLIFF_TIME(); uint40 endTime = defaults.END_TIME(); - vm.expectRevert(Errors.SablierV2LockupLinear_StartTimeZero.selector); + vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); createDefaultStreamWithRange(LockupLinear.Range({ start: 0, cliff: cliffTime, end: endTime })); } @@ -62,6 +67,8 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is external whenNotDelegateCalled whenRecipientNonZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeZero { uint40 startTime = defaults.END_TIME(); @@ -80,6 +87,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeZero { createDefaultStreamWithRange( @@ -112,6 +120,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero { uint40 startTime = defaults.CLIFF_TIME(); @@ -130,6 +139,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime { @@ -149,6 +159,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime @@ -165,6 +176,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime @@ -182,6 +194,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime @@ -198,6 +211,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime @@ -212,6 +226,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is external whenNotDelegateCalled whenDepositAmountNotZero + whenStartTimeNotZero whenCliffTimeGreaterThanZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index aabc6eada..09f7524ad 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -49,11 +49,22 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is createDefaultStreamWithTotalAmount(totalAmount); } + function test_RevertWhen_StartTimeZero() + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + { + vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); + createDefaultStreamWithStartTime(0); + } + function test_RevertWhen_TrancheCountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero { LockupTranched.Tranche[] memory tranches; vm.expectRevert(Errors.SablierV2LockupTranched_TrancheCountZero.selector); @@ -65,6 +76,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero { uint256 trancheCount = defaults.MAX_COUNT() + 1; @@ -80,6 +92,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh { @@ -95,6 +108,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -121,6 +135,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -147,6 +162,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -176,6 +192,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -193,6 +210,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -230,6 +248,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -250,6 +269,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -273,6 +293,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -291,6 +312,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree index 81617ee76..4ffd8d5a5 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -8,46 +8,49 @@ createWithTimestamps.t.sol ├── when the deposit amount is zero │ └── it should revert └── when the deposit amount is not zero - ├── when the tranche count is zero + ├── when the start time is zero │ └── it should revert - └── when the tranche count is not zero - ├── when the tranche count is too high + └── when the start time is not zero + ├── when the tranche count is zero │ └── it should revert - └── when the tranche count is not too high - ├── when the tranche amounts sum overflows + └── when the tranche count is not zero + ├── when the tranche count is too high │ └── it should revert - └── when the tranche amounts sum does not overflow - ├── when the start time is greater than the first tranche timestamp + └── when the tranche count is not too high + ├── when the tranche amounts sum overflows │ └── it should revert - ├── when the start time is equal to the first tranche timestamp - │ └── it should revert - └── when the start time is less than the first tranche timestamp - ├── when the tranche timestamps are not ordered + └── when the tranche amounts sum does not overflow + ├── when the start time is greater than the first tranche timestamp + │ └── it should revert + ├── when the start time is equal to the first tranche timestamp │ └── it should revert - └── when the tranche timestamps are ordered - ├── when the end time is not in the future + └── when the start time is less than the first tranche timestamp + ├── when the tranche timestamps are not ordered │ └── it should revert - └── when the end time is in the future - ├── when the deposit amount is not equal to the tranche amounts sum + └── when the tranche timestamps are ordered + ├── when the end time is not in the future │ └── it should revert - └── when the deposit amount is equal to the tranche amounts sum - ├── when the broker fee is too high + └── when the end time is in the future + ├── when the deposit amount is not equal to the tranche amounts sum │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract + └── when the deposit amount is equal to the tranche amounts sum + ├── when the broker fee is too high │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream id - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupTranchedStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream id - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupTranchedStream} event + └── when the broker fee is not too high + ├── when the asset is not a contract + │ └── it should revert + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream id + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupTranchedStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream id + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupTranchedStream} event diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index a5f279d39..cce900d40 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -177,6 +177,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenSegmentCountNotZero whenSegmentCountNotTooHigh whenSegmentAmountsSumDoesNotOverflow @@ -191,7 +192,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is vm.assume(funder != address(0) && params.recipient != address(0) && params.broker.account != address(0)); vm.assume(params.segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); params.transferable = true; // Fuzz the segment timestamps. diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index bc53ce6fd..9a92d315e 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -104,6 +104,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is external whenNotDelegateCalled whenDepositAmountNotZero + whenStartTimeNotZero whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 4b25dd2e0..7d197ae39 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -177,6 +177,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero + whenStartTimeNotZero whenTrancheCountNotZero whenTrancheCountNotTooHigh whenTrancheAmountsSumDoesNotOverflow @@ -192,7 +193,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is vm.assume(params.tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, defaults.START_TIME()); + params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); params.transferable = true; // Fuzz the tranche timestamps. diff --git a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol index 3b1b3c53e..b9a7a5fd2 100644 --- a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol @@ -22,6 +22,10 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupDynamic_Integrati _; } + modifier whenStartTimeNotZero() { + _; + } + modifier whenSegmentCountNotZero() { _; } diff --git a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol index ebe9f366d..09975a86c 100644 --- a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol @@ -22,6 +22,10 @@ abstract contract CreateWithTimestamps_Integration_Shared_Test is LockupLinear_I _; } + modifier whenStartTimeNotZero() { + _; + } + modifier whenStartTimeNotGreaterThanCliffTime() { _; } diff --git a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol index 88ff66f17..854d97960 100644 --- a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol @@ -22,6 +22,10 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupTranched_Integrat _; } + modifier whenStartTimeNotZero() { + _; + } + modifier whenTrancheCountNotZero() { _; } diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index 9db2edcc4..8ec23a98d 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -95,6 +95,15 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } + function invariant_DepositedAmountNotZero() external useCurrentTimestamp { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + uint128 depositAmount = lockup.getDepositedAmount(streamId); + assertNotEq(depositAmount, 0, "Invariant violated: stream non-null, deposited amount zero"); + } + } + function invariant_EndTimeGtStartTime() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { @@ -115,6 +124,15 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } + function invariant_StartTimeNotZero() external useCurrentTimestamp { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + uint40 startTime = lockup.getStartTime(streamId); + assertGt(startTime, 0, "Invariant violated: start time zero"); + } + } + function invariant_StatusCanceled() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index cc7d75d29..ac99bfd53 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -58,26 +58,6 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { INVARIANTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The deposited amount must not be zero. - function invariant_DepositedAmountNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupDynamic.StreamLD memory stream = lockupDynamic.getStream(streamId); - assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); - } - } - - /// @dev The end time cannot be zero because it must be greater than the start time (which can be zero). - function invariant_EndTimeNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupDynamic.StreamLD memory stream = lockupDynamic.getStream(streamId); - assertNotEq(stream.endTime, 0, "Invariant violated: end time zero"); - } - } - /// @dev Unordered segment timestamps are not allowed. function invariant_SegmentTimestampsOrdered() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index 84ac74858..bca4387eb 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -73,16 +73,6 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { } } - /// @dev The deposited amount must not be zero. - function invariant_DepositedAmountNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupLinear.StreamLL memory stream = lockupLinear.getStream(streamId); - assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); - } - } - /// @dev The end time must not be less than or equal to the cliff time. function invariant_EndTimeGtCliffTime() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); @@ -96,16 +86,6 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { } } - /// @dev The end time must not be zero because it must be greater than the start time (which can be zero). - function invariant_EndTimeNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupLinear.StreamLL memory stream = lockupLinear.getStream(streamId); - assertNotEq(stream.endTime, 0, "Invariant violated: stream non-null, end time zero"); - } - } - /// @dev Settled streams must not appear as cancelable in {SablierV2LockupLinear.getStream}. function invariant_StatusSettled_GetStream() external { uint256 lastStreamId = lockupStore.lastStreamId(); diff --git a/test/invariant/LockupTranched.t.sol b/test/invariant/LockupTranched.t.sol index c57c3e177..e076af08a 100644 --- a/test/invariant/LockupTranched.t.sol +++ b/test/invariant/LockupTranched.t.sol @@ -58,26 +58,6 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { INVARIANTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The deposited amount must not be zero. - function invariant_DepositedAmountNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupTranched.StreamLT memory stream = lockupTranched.getStream(streamId); - assertNotEq(stream.amounts.deposited, 0, "Invariant violated: stream non-null, deposited amount zero"); - } - } - - /// @dev The end time cannot be zero because it must be greater than the start time (which can be zero). - function invariant_EndTimeNotZero() external useCurrentTimestamp { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupTranched.StreamLT memory stream = lockupTranched.getStream(streamId); - assertNotEq(stream.endTime, 0, "Invariant violated: end time zero"); - } - } - /// @dev Settled streams must not appear as cancelable in {SablierV2LockupTranched.getStream}. function invariant_StatusSettled_GetStream() external { uint256 lastStreamId = lockupStore.lastStreamId(); diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 44e4b8dec..4cd0f7d7f 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -109,7 +109,7 @@ contract LockupDynamicCreateHandler is BaseHandler { } params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); + params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); // Fuzz the segment timestamps. fuzzSegmentTimestamps(params.segments, params.startTime); diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/invariant/handlers/LockupTranchedCreateHandler.sol index 91a95740d..6661a7863 100644 --- a/test/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/invariant/handlers/LockupTranchedCreateHandler.sol @@ -109,7 +109,7 @@ contract LockupTranchedCreateHandler is BaseHandler { } params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 0, getBlockTimestamp()); + params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); // Fuzz the tranche timestamps. fuzzTrancheTimestamps(params.tranches, params.startTime); From 871a75d8399a27cb78266c36522d1f0f7dd78f0f Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 18 Mar 2024 12:54:14 +0000 Subject: [PATCH 067/132] test: fix error in lockup linear's streamedAmountOf branching tree --- .../lockup-linear/streamed-amount-of/streamedAmountOf.tree | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree index 9c23e5349..4a8e35c69 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree @@ -4,5 +4,5 @@ streamedAmountOf.t.sol │ └── it should return zero ├── given the cliff time is in the present │ └── it should return the correct streamed amount - └── given the cliff time is not in the future + └── given the cliff time is in the future └── it should return the correct streamed amount From 0455ff577a53b06ba2c429f5c246b53ea43c8fb7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 18 Mar 2024 16:54:35 +0000 Subject: [PATCH 068/132] test: MAX_BROKER_FEE (#855) --- test/integration/concrete/lockup-dynamic/constructor.t.sol | 6 ++++++ test/integration/concrete/lockup-linear/constructor.t.sol | 6 ++++++ test/integration/concrete/lockup-tranched/constructor.t.sol | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index 817d6277a..41c339147 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2LockupDynamic } from "src/SablierV2LockupDynamic.sol"; import { LockupDynamic_Integration_Concrete_Test } from "./LockupDynamic.t.sol"; @@ -18,6 +19,11 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In maxSegmentCount: defaults.MAX_COUNT() }); + // {SablierV2Lockup.constant} + UD60x18 actualMaxBrokerFee = constructedLockupDynamic.MAX_BROKER_FEE(); + UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); + assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupDynamic.admin(); address expectedAdmin = users.admin; diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index ff221e8b9..42db1d881 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2LockupLinear } from "src/SablierV2LockupLinear.sol"; import { LockupLinear_Integration_Concrete_Test } from "./LockupLinear.t.sol"; @@ -15,6 +16,11 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte SablierV2LockupLinear constructedLockupLinear = new SablierV2LockupLinear({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor }); + // {SablierV2Lockup.constant} + UD60x18 actualMaxBrokerFee = constructedLockupLinear.MAX_BROKER_FEE(); + UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); + assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupLinear.admin(); address expectedAdmin = users.admin; diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol index bda7ba84f..bb7d729e0 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { SablierV2LockupTranched } from "src/SablierV2LockupTranched.sol"; import { LockupTranched_Integration_Concrete_Test } from "./LockupTranched.t.sol"; @@ -18,6 +19,11 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ maxTrancheCount: defaults.MAX_COUNT() }); + // {SablierV2Lockup.constant} + UD60x18 actualMaxBrokerFee = constructedLockupTranched.MAX_BROKER_FEE(); + UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); + assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); + // {SablierV2Lockup.constructor} address actualAdmin = constructedLockupTranched.admin(); address expectedAdmin = users.admin; From 1b2ee6df156b156799a4e3bd680b726079b018fb Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 18 Mar 2024 23:51:14 +0200 Subject: [PATCH 069/132] refactor: use if statement instead of ternary operator chore: update Precompiles --- precompiles/Precompiles.sol | 2 +- src/SablierV2LockupLinear.sol | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 472588760..211c84b50 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -27,7 +27,7 @@ contract Precompiles { bytes public constant BYTECODE_LOCKUP_DYNAMIC = hex"60c034620003dc576001600160401b0390601f601f1962005a3b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156399081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab826141c7565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141c7565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b657610713846141c7565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614605565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161465f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d8588614605565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614197565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a6141c7565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be916141ef565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b87825285522001541694613151818988614605565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e6134378361465f565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b916141ef565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c88614605565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a8906142db565b90565b6137a89061420a565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b0360408401511660206101008501510151906144bb565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b038351169030903390614594565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b036101008601515116903390614594565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b515116906141ef565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b3d156141c2573d906141a8826129b2565b916141b66040519384612990565b82523d6000602084013e565b606090565b6137a8906141d48161465f565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff61423f600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146da565b91808252600a602052604082208054156142c75790829167ffffffffffffffff9352614299602083205482845260096020526142946001600160801b03968760026040882001541696879360801c16906147ca565b614838565b9283136142af5750506142ab90614922565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161430183612973565b80549661012061438760026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a60205261439e858520612df7565b91849680876143ac866139f8565b5101511692828288955b161061448557509161443a6142949284888161443f98976001600160801b039e8f6143e1898c613a05565b5151169d8e9a67ffffffffffffffff60206143fc8c84613a05565b5101511699848361440d8385613a05565b5101511696508015614479576144299293506000190190613a05565b5101511680925b03169203166146da565b6147ca565b9283136144585750506144528391614922565b16011690565b5160200151929392831692841683101591506144749050575090565b905090565b50505051168092614430565b8093986001600160801b03908161449c8c89613a05565b51511601169801928282808a6144b2888a613a05565b510151166143b6565b919091604051906144cb82612943565b600091828152826020820152936001600160801b03928383169182156145755767016345785d8a000080821161453e57506145078591846154ea565b166020870192818452111561452a5750908261452592511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061458982612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb576146039260405261495e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146039161465a606483612990565b61495e565b8060005260096020526146786002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146146ab57506001600160801b039150602001511690565b5460f81c6146bd57506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b600160ff1b8082149081156147c0575b5061479657600081121561478d57614713816000035b60008412156147865783600003906149fa565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474f57600019911813156147495790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fa565b61471381614700565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ea565b806147e557506147e057670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483257508061480a575050670de0b6b3a764000090565b670de0b6b3a7640000811461482e57614829906142946137a893614af4565b614c36565b5090565b91505090565b600160ff1b808214908115614918575b506148ee5760008112156148e557614871816000035b60008412156148de5783600003906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a757600019911813156147495790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ea565b6148718161485e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614848565b6000811261492d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614989600080836020829551910182875af1614982614197565b9084615599565b9081519182151592836149d2575b5050506149a15750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614997565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab65782851015614a7a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac4570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac4576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0557670de0b6b3a764000092838112614be257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd657506706f05b59d3b20000905b848213614baa5750505050500290565b808391020590671bc16d674ec80000821215614bc9575b831d90614b9a565b8091950194831d90614bc1565b93505093925050020290565b6000199392508015614ac4576ec097ce7bc90715b34b9f10000000000591614b15565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c655768033dd1780914b9711419811261384a57614c5c90600003614c36565b6137a890614ada565b680a688906bd8affffff81136154b957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539c575b66ff0000000000008316615294575b65ff00000000008316615194575b64ff00000000831661509c575b63ff0000008316614fac575b62ff00008316614ec4575b61ff008316614de4575b60ff8316614d0d575b02911c60bf031c90565b60808316614dd2575b838316614dc0575b60208316614dae575b60108316614d9c575b60088316614d8a575b60048316614d78575b60028316614d66575b6001831615614d03576801000000000000000102831c614d03565b6801000000000000000102831c614d4b565b6801000000000000000302831c614d42565b6801000000000000000602831c614d39565b6801000000000000000b02831c614d30565b6801000000000000001602831c614d27565b6801000000000000002c02831c614d1e565b6801000000000000005902831c614d16565b6180008316614eb2575b6140008316614ea0575b6120008316614e8e575b6110008316614e7c575b6108008316614e6a575b6104008316614e58575b6102008316614e46575b610100831615614cfa57680100000000000000b102831c614cfa565b6801000000000000016302831c614e2a565b680100000000000002c602831c614e20565b6801000000000000058c02831c614e16565b68010000000000000b1702831c614e0c565b6801000000000000162e02831c614e02565b68010000000000002c5d02831c614df8565b680100000000000058b902831c614dee565b628000008316614f9a575b624000008316614f88575b622000008316614f76575b621000008316614f64575b620800008316614f52575b620400008316614f40575b620200008316614f2e575b62010000831615614cf0576801000000000000b17202831c614cf0565b680100000000000162e402831c614f11565b6801000000000002c5c802831c614f06565b68010000000000058b9102831c614efb565b680100000000000b172102831c614ef0565b68010000000000162e4302831c614ee5565b680100000000002c5c8602831c614eda565b6801000000000058b90c02831c614ecf565b6380000000831661508a575b63400000008316615078575b63200000008316615066575b63100000008316615054575b63080000008316615042575b63040000008316615030575b6302000000831661501e575b6301000000831615614ce55768010000000000b1721802831c614ce5565b6801000000000162e43002831c615000565b68010000000002c5c86002831c614ff4565b680100000000058b90c002831c614fe8565b6801000000000b17217f02831c614fdc565b680100000000162e42ff02831c614fd0565b6801000000002c5c85fe02831c614fc4565b68010000000058b90bfc02831c614fb8565b6480000000008316615182575b6440000000008316615170575b642000000000831661515e575b641000000000831661514c575b640800000000831661513a575b6404000000008316615128575b6402000000008316615116575b640100000000831615614cd957680100000000b17217f802831c614cd9565b68010000000162e42ff102831c6150f7565b680100000002c5c85fe302831c6150ea565b6801000000058b90bfce02831c6150dd565b68010000000b17217fbb02831c6150d0565b6801000000162e42fff002831c6150c3565b68010000002c5c8601cc02831c6150b6565b680100000058b90c0b4902831c6150a9565b658000000000008316615282575b654000000000008316615270575b65200000000000831661525e575b65100000000000831661524c575b65080000000000831661523a575b650400000000008316615228575b650200000000008316615216575b65010000000000831615614ccc576801000000b17218355102831c614ccc565b680100000162e430e5a202831c6151f6565b6801000002c5c863b73f02831c6151e8565b68010000058b90cf1e6e02831c6151da565b680100000b1721bcfc9a02831c6151cc565b68010000162e43f4f83102831c6151be565b680100002c5c89d5ec6d02831c6151b0565b6801000058b91b5bc9ae02831c6151a2565b6680000000000000831661538a575b66400000000000008316615378575b66200000000000008316615366575b66100000000000008316615354575b66080000000000008316615342575b66040000000000008316615330575b6602000000000000831661531e575b6601000000000000831615614cbe5768010000b17255775c0402831c614cbe565b6801000162e525ee054702831c6152fd565b68010002c5cc37da949202831c6152ee565b680100058ba01fb9f96d02831c6152df565b6801000b175effdc76ba02831c6152d0565b680100162f3904051fa102831c6152c1565b6801002c605e2e8cec5002831c6152b2565b68010058c86da1c09ea202831c6152a3565b678000000000000000831661549a575b6740000000000000008316615488575b6720000000000000008316615476575b6710000000000000008316615464575b6708000000000000008316615452575b6704000000000000008316615440575b670200000000000000831661542e575b670100000000000000831615614caf57680100b1afa5abcbed6102831c614caf565b68010163da9fb33356d802831c61540c565b680102c9a3e778060ee702831c6153fc565b6801059b0d31585743ae02831c6153ec565b68010b5586cf9890f62a02831c6153dc565b6801172b83c7d517adce02831c6153cc565b6801306fe0a31b7152df02831c6153bc565b5077b504f333f9de6484800000000000000000000000000000006153ac565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558857670de0b6b3a7640000908183101561555157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d857508051156155ae57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615623575b6155e9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e156fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f620049a33881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c69081620003dd8239608051816139480152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5f57508063027b674414612f3c57806306fdde0314612e77578063081812fc14612e58578063095ea7b314612d5f5780631400ecec14612cbf5780631c1cdd4c14612c5a5780631e99d56914612c3c57806323b872dd14612c2457806340e58ee5146129a6578063425d30dd1461295557806342842e0e1461290557806342966c681461272a57806344267570146127035780634857501f1461268d5780634869e12d146126525780634cc55e11146121c257806353b15727146120a35780636352211e146120735780636d0cee751461207357806370a082311461200357806375829def14611f70578063780a82c814611f235780637cad6cd114611e295780637de6b1db14611c025780638659c270146118b1578063894e9a0d146115915780638f69b993146114f55780639067b677146114a557806395d89b4114611396578063a22cb465146112d9578063a80fc07114611287578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f61308e565b916102786131eb565b9261028161393e565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140b1565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134e2565b906103b181868401511692826040818351169201511690613225565b161115610532575b848c528252600160408c20015416946103d3818a886140dc565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b6104919061310a565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b6105199061310a565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d58961399a565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576004359061074761308e565b91610278816140b1565b503461064c57604036600319011261064c5761076b613078565b604061077561308e565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140b1565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134c3565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b8561313b565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613697565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e6604051928284938452830190613053565b0390f35b909192503d8082843e6109fd81846131ad565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131cf565b93610a4160405195866131ad565b83855285848401011161064c575090610a5f91848085019101613030565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a9461308e565b610a9c61393e565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140b1565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f9565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b61393e565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140b1565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613225565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140dc565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c9061310a565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e009061310a565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a61399a565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613078565b61101a61308e565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131cf565b9361105760405195866131ad565b8585523660248783010111610a6757856110829660246020930183880137850101526044359161352a565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f90613772565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c5761115361393e565b61115b6134c3565b9064ffffffffff80421680845281611171613516565b1615611280578180611181613516565b8301165b16602085015260e43590828216820361127b5701166040830152600435916001600160a01b039182841680940361127b576024359083821680920361127b57604435906001600160801b03821680920361127b576064359085821680920361064c57506084359182151580930361127b5760a4359384151580950361127b57604051976112118961311e565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261127b576040519161124b83613191565b61010435918216820361127b57826112739260209452610124358482015260e0820152613a03565b604051908152f35b600080fd5b8183611185565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112f3613078565b6024359081151580920361127b576001600160a01b03169081156113655733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c926001851694851561149b575b60209586861081146114875785885287949392918790821561146557505060011461140b575b50506113f7925003836131ad565b6109e6604051928284938452830190613053565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144d5750506113f7935082010138806113e9565b80548389018501528794508693909201918101611435565b92509350506113f794915060ff191682840152151560051b82010138806113e9565b602483634e487b7160e01b81526022600452fd5b93607f16936113c3565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761152e90613772565b906005821015908161156f5760028314918215611583575b821561155a575b6020836040519015158152f35b90915061156f5750600460209114388061154d565b80634e487b7160e01b602492526021600452fd5b506003831491506000611546565b503461064c57602036600319011261064c57806101606040516115b381613157565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f66134c3565b61014082015201526004358152600960205260ff600160408320015460a81c1615611899576004358152600960205260408120906116c460026040519361163c85613174565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134e2565b6101208301526116d5600435613772565b6005811015611885576101606101c093600264ffffffffff931461187a575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117818d613157565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f4565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118e49036906004016130d9565b91906118ee61393e565b83925b8084106118fc578480f35b61190784828461349d565b359361191161393e565b848652600980855260ff90600190828260408b20015460a81c1615611beb57878952808752604089208281015460a01c8416156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd3576119918160005260096020526001600160a01b0360406000205416331490565b15611bb35761199f816136ba565b818a528289526119b4600260408c20016134e2565b906001600160801b0395868351168783161015611b9b57838c52848b5260408c205460f01c1615611b835791818a611a0585898f9a9998966119fb8c998387935116613225565b9501511690613225565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b6a575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaf8b85886140dc565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b13575b5050505050506001019291906118f1565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b56575b80808080611b02565b611b5f9061310a565b610524578438611b4d565b818601600160a01b60ff60a01b19825416179055611a6a565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c2161393e565b8183526009815260ff600160408520015460a81c1615611e1257611c4482613772565b6005811015611dfe5760048103611c6d5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8d576024836040519063fe19f19f60e01b82526004820152fd5b600214611de657611cb48260005260096020526001600160a01b0360406000205416331490565b15611dc7578183526009815260ff604084205460f01c1615611daf57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d57575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9b575b80611d28565b611da49061310a565b61049c578238611d95565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611efa575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f8a613078565b9080546001600160a01b0380821693338503611fdc576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612025613078565b168015612042578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c576020612092600435613697565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120be61393e565b604051906120cb8261311e565b6120d3613078565b82526120dd61308e565b60208301526120ea6131eb565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361127b57608084015260a435801515810361127b5760a084015260603660c319011261064c57506040516121448161313b565b64ffffffffff60c435818116810361127b57825260e435818116810361127b57602083015261010435908116810361127b57604082015260c083015260406101231936011261127b576040519161219a83613191565b61012435918216820361127b57826112739260209452610144358482015260e0820152613a03565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f59036906004016130d9565b90916024359081116104a05761220f9036906004016130d9565b61221761393e565b80830361261b57845b83811061222b578580f35b61223681858761349d565b359061224381868861349d565b35875260036020526001600160a01b0360408820541661226482858761349d565b35906001600160801b038216820361127b5761227e61393e565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156126035783895260036020526001600160a01b0360408a2054169182821415806125f3575b6125cf576122f6856140b1565b6001600160801b0381166001600160801b0383161161259f5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123878c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ab8160208401511692826040818351169201511690613225565b16111561256e575b86855260096020526001600160a01b036001604087200154166123e06001600160801b03841685836140dc565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612564575b6124fa575b8333141590816124ef575b816124e4575b50612472575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612220565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124cc575b808061243b565b6124d59061310a565b6124e05786386124c5565b8680fd5b905083141538612435565b843b1515915061242f565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612550575b5050612424565b6125599061310a565b610524578438612549565b50803b151561241f565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b3565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125fd8561399a565b156122e9565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614138565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257806126c883613772565b926005841015611885576002602094036126e9575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126dd565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a67576004359061274961393e565b8183526009815260ff600160408520015460a81c1615611e12578183526009815260ff600160408520015460a01c16156128d4576127868261399a565b15611dc75781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128ca575b50806128c2575b6128aa577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286f575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612857575080f35b60249060405190637e27328960e01b82526004820152fd5b61289085600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612805565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c5565b90501515386127be565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57612914366130a4565b60405191602083019383851067ffffffffffffffff86111761293f576110829460405285845261352a565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c661393e565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a145760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bd357612a3f8160005260096020526001600160a01b0360406000205416331490565b15611bb357612a4d816136ba565b93818452808352612a63600260408620016134e2565b916001600160801b0393848451168588161015611de65781865282815260ff604087205460f01c1615611daf57612ab1878683612aa78a9b838a9c9b9c5116613225565b9701511690613225565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c0a575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b3d8c84876140dc565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb9578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bfb575b81818080808480f35b612c049061310a565b81612bf2565b60018101600160a01b60ff60a01b19825416179055612af6565b503461064c57611082612c36366130a4565b91613254565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c9390613772565b90600582101561156f5760208215838115612cb4575b506040519015158152f35b600191501482612ca9565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e1257602091604082828152600985522060ff815460f01c1680612d4d575b612d24575b50506001600160801b0360405191168152f35b612d4692506001600160801b036002612d4092015416916136ba565b90613225565b3880612d11565b5060ff600182015460a01c1615612d0c565b503461064c57604036600319011261064c57612d79613078565b602435612d8581613697565b33151580612e45575b80612e1b575b612deb5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d94565b50336001600160a01b0382161415612d8e565b503461064c57602036600319011261064c576020612092600435613201565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f32575b602095868610811461148757858852879493929187908215611465575050600114612ed85750506113f7925003836131ad565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f1a5750506113f7935082010138806113e9565b80548389018501528794508693909201918101612f02565b93607f1693612ea5565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613006575b8115612fdc575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fce565b60005b8381106130435750506000910152565b8181015183820152602001613033565b9060209161306c81518092818552858086019101613030565b601f01601f1916010190565b600435906001600160a01b038216820361127b57565b602435906001600160a01b038216820361127b57565b606090600319011261127b576001600160a01b0390600435828116810361127b5791602435908116810361127b579060443590565b9181601f8401121561127b5782359167ffffffffffffffff831161127b576020808501948460051b01011161127b57565b67ffffffffffffffff811161293f57604052565b610100810190811067ffffffffffffffff82111761293f57604052565b6060810190811067ffffffffffffffff82111761293f57604052565b610180810190811067ffffffffffffffff82111761293f57604052565b610140810190811067ffffffffffffffff82111761293f57604052565b6040810190811067ffffffffffffffff82111761293f57604052565b90601f8019910116810190811067ffffffffffffffff82111761293f57604052565b67ffffffffffffffff811161293f57601f01601f191660200190565b604435906001600160801b038216820361127b57565b61320a81613697565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323e57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348557600091848352602091600383526040928284862054166009825260ff6001868820015460b01c1615908161347b575b5080613473575b61345c5786855260038152828486205416948733151593846133ac575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613374575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133465750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339582600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132e2565b9192938091509061341b575b156133c657908783926132b9565b8488876133e3576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613440575b806133b857508782526005835233848684205416146133b8565b5085825260068352848220338352835260ff8583205416613426565b602487855190630da9b01360e01b82526004820152fd5b50600161329c565b9050151538613295565b6024604051633250574960e11b815260006004820152fd5b91908110156134ad5760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134d08261313b565b60006040838281528260208201520152565b906040516134ef8161313b565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361127b5790565b9190613537828285613254565b803b613544575b50505050565b6135a06001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613053565b03906020816000938185885af190829082613636575b50506135ed57826135c5614081565b80519190826135e65760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361361e57503880808061353e565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368f575b81613653602093836131ad565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b6565b3d9150613646565b8060005260036020526001600160a01b0360406000205416908115612857575090565b600090808252600a60205264ffffffffff9182604082205416421061376c5760096020526040812092835490808260c81c1691824210156137565761370b9394955060a01c168091039042036142fb565b9082815260096020526001600160801b03926137318460026040852001541680946143db565b92831161373e5750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613799575050600490565b805460f81c6137f2575460a01c64ffffffffff1642106137ec576137bc816136ba565b9060005260096020526001600160801b0380600260406000200154169116106000146137e757600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613934575b5080613929575b613912579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138da575b1692836138c4575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a0565b6138fb86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613898565b602486885190630da9b01360e01b82526004820152fd5b508181161515613837565b9050151538613830565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361397057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139df575b505082156139cd57505090565b9091506139da3392613201565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139c0565b90613a246001600160801b03604084015116602060e08501510151906141b3565b916001600160801b0383511660c082015190156140575764ffffffffff8151161561402d5764ffffffffff81511690604081019164ffffffffff8351169081811015613fed575050602081019064ffffffffff8251169081151580613fdb575b613f9a57505064ffffffffff90511664ffffffffff8251169081811015613f5a57505064ffffffffff8042169151169081811015613f1a575050600754926001600160801b0381511660405190613ada8261313b565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b3c88613174565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d3484875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613efc575b50600184016007556001600160a01b03602083015116801561348557613d84856001600160a01b03926137f9565b16613ecb57613daf6001600160a01b036060840151166001600160801b03835116903090339061428c565b6001600160801b0360208201511680613e9c575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e936001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec5906001600160a01b036060850151166001600160a01b0360e0860151511690339061428c565b38613dc3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d56565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a84565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140ac573d90614092826131cf565b916140a060405193846131ad565b82523d6000602084013e565b606090565b6140d9906140be81614138565b90600052600960205260026040600020015460801c90613225565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152614136916141316064836131ad565b61448a565b565b80600052600960205261415160026040600020016134e2565b816000526009602052604060002060ff600182015460a01c1660001461418457506001600160801b039150602001511690565b5460f81c61419657506140d9906136ba565b6140d991506001600160801b036040818351169201511690613225565b919091604051906141c382613191565b600091828152826020820152936001600160801b039283831691821561426d5767016345785d8a000080821161423657506141ff8591846143db565b16602087019281845211156142225750908261421d92511690613225565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061428182613191565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293f576141369260405261448a565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b7578285101561437b57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c5570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447957670de0b6b3a7640000908183101561444257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b5600080836020829551910182875af16144ae614081565b9084614526565b9081519182151592836144fe575b5050506144cd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144c3565b90614565575080511561453b57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145b0575b614576575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456e56fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f6200499e3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c19081620003dd8239608051816139430152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5a57508063027b674414612f3757806306fdde0314612e72578063081812fc14612e53578063095ea7b314612d5a5780631400ecec14612cba5780631c1cdd4c14612c555780631e99d56914612c3757806323b872dd14612c1f57806340e58ee5146129a1578063425d30dd1461295057806342842e0e1461290057806342966c681461272557806344267570146126fe5780634857501f146126885780634869e12d1461264d5780634cc55e11146121bd57806353b157271461209e5780636352211e1461206e5780636d0cee751461206e57806370a0823114611ffe57806375829def14611f6b578063780a82c814611f1e5780637cad6cd114611e245780637de6b1db14611bfd5780638659c270146118ac578063894e9a0d1461158c5780638f69b993146114f05780639067b677146114a057806395d89b4114611391578063a22cb465146112d4578063a80fc07114611282578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613089565b916102786131e6565b92610281613939565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140ac565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134dd565b906103b181868401511692826040818351169201511690613220565b161115610532575b848c528252600160408c20015416946103d3818a886140d7565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613105565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613105565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613995565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613089565b91610278816140ac565b503461064c57604036600319011261064c5761076b613073565b6040610775613089565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140ac565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134be565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613136565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613692565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061304e565b0390f35b909192503d8082843e6109fd81846131a8565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131ca565b93610a4160405195866131a8565b83855285848401011161064c575090610a5f9184808501910161302b565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613089565b610a9c613939565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140ac565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f4565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613939565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140ac565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613220565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140d7565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c90613105565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e0090613105565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613995565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613073565b61101a613089565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131ca565b9361105760405195866131a8565b8585523660248783010111610a67578561108296602460209301838801378501015260443591613525565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061376d565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613939565b61115b6134be565b9064ffffffffff80421680845281611171613511565b1661126c575b60e4359082821682036112675701166040830152600435916001600160a01b0391828416809403611267576024359083821680920361126757604435906001600160801b038216809203611267576064359085821680920361064c5750608435918215158093036112675760a4359384151580950361126757604051976111fd89613119565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126757604051916112378361318c565b610104359182168203611267578261125f9260209452610124358482015260e08201526139fe565b604051908152f35b600080fd5b81611275613511565b8201166020850152611177565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112ee613073565b60243590811515809203611267576001600160a01b03169081156113605733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c9260018516948515611496575b602095868610811461148257858852879493929187908215611460575050600114611406575b50506113f2925003836131a8565b6109e660405192828493845283019061304e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106114485750506113f2935082010138806113e4565b80548389018501528794508693909201918101611430565b92509350506113f294915060ff191682840152151560051b82010138806113e4565b602483634e487b7160e01b81526022600452fd5b93607f16936113be565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576115299061376d565b906005821015908161156a576002831491821561157e575b8215611555575b6020836040519015158152f35b90915061156a57506004602091143880611548565b80634e487b7160e01b602492526021600452fd5b506003831491506000611541565b503461064c57602036600319011261064c57806101606040516115ae81613152565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f16134be565b61014082015201526004358152600960205260ff600160408320015460a81c1615611894576004358152600960205260408120906116bf6002604051936116378561316f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134dd565b6101208301526116d060043561376d565b6005811015611880576101606101c093600264ffffffffff9314611875575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b61177c8d613152565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116ef565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118df9036906004016130d4565b91906118e9613939565b83925b8084106118f7578480f35b611902848284613498565b359361190c613939565b848652600980855260ff90600190828260408b20015460a81c1615611be657878952808752604089208281015460a01c84161561195b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bce5761198c8160005260096020526001600160a01b0360406000205416331490565b15611bae5761199a816136b5565b818a528289526119af600260408c20016134dd565b906001600160801b0395868351168783161015611b9657838c52848b5260408c205460f01c1615611b7e5791818a611a0085898f9a9998966119f68c998387935116613220565b9501511690613220565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b65575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaa8b85886140d7565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b0e575b5050505050506001019291906118ec565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b51575b80808080611afd565b611b5a90613105565b610524578438611b48565b818601600160a01b60ff60a01b19825416179055611a65565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c1c613939565b8183526009815260ff600160408520015460a81c1615611e0d57611c3f8261376d565b6005811015611df95760048103611c685760248360405190634a5541ef60e01b82526004820152fd5b60038103611c88576024836040519063fe19f19f60e01b82526004820152fd5b600214611de157611caf8260005260096020526001600160a01b0360406000205416331490565b15611dc2578183526009815260ff604084205460f01c1615611daa57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d52575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d96575b80611d23565b611d9f90613105565b61049c578238611d90565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ef5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee15760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f85613073565b9080546001600160a01b0380821693338503611fd7576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612020613073565b16801561203d578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061208d600435613692565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120b9613939565b604051906120c682613119565b6120ce613073565b82526120d8613089565b60208301526120e56131e6565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361126757608084015260a43580151581036112675760a084015260603660c319011261064c575060405161213f81613136565b64ffffffffff60c435818116810361126757825260e435818116810361126757602083015261010435908116810361126757604082015260c083015260406101231936011261126757604051916121958361318c565b610124359182168203611267578261125f9260209452610144358482015260e08201526139fe565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f09036906004016130d4565b90916024359081116104a05761220a9036906004016130d4565b612212613939565b80830361261657845b838110612226578580f35b612231818587613498565b359061223e818688613498565b35875260036020526001600160a01b0360408820541661225f828587613498565b35906001600160801b038216820361126757612279613939565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125fe5783895260036020526001600160a01b0360408a2054169182821415806125ee575b6125ca576122f1856140ac565b6001600160801b0381166001600160801b0383161161259a5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123828c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123a68160208401511692826040818351169201511690613220565b161115612569575b86855260096020526001600160a01b036001604087200154166123db6001600160801b03841685836140d7565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061255f575b6124f5575b8333141590816124ea575b816124df575b5061246d575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161221b565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c7575b8080612436565b6124d090613105565b6124db5786386124c0565b8680fd5b905083141538612430565b843b1515915061242a565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161254b575b505061241f565b61255490613105565b610524578438612544565b50803b151561241a565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123ae565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f885613995565b156122e4565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614133565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57806126c38361376d565b926005841015611880576002602094036126e4575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126d8565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612744613939565b8183526009815260ff600160408520015460a81c1615611e0d578183526009815260ff600160408520015460a01c16156128cf5761278182613995565b15611dc25781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128c5575b50806128bd575b6128a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612852575080f35b60249060405190637e27328960e01b82526004820152fd5b61288b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612800565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c0565b90501515386127b9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c5761290f3661309f565b60405191602083019383851067ffffffffffffffff86111761293a5761108294604052858452613525565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c1613939565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a0f5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bce57612a3a8160005260096020526001600160a01b0360406000205416331490565b15611bae57612a48816136b5565b93818452808352612a5e600260408620016134dd565b916001600160801b0393848451168588161015611de15781865282815260ff604087205460f01c1615611daa57612aac878683612aa28a9b838a9c9b9c5116613220565b9701511690613220565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c05575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b388c84876140d7565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb4578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bf6575b81818080808480f35b612bff90613105565b81612bed565b60018101600160a01b60ff60a01b19825416179055612af1565b503461064c57611082612c313661309f565b9161324f565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c8e9061376d565b90600582101561156a5760208215838115612caf575b506040519015158152f35b600191501482612ca4565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57602091604082828152600985522060ff815460f01c1680612d48575b612d1f575b50506001600160801b0360405191168152f35b612d4192506001600160801b036002612d3b92015416916136b5565b90613220565b3880612d0c565b5060ff600182015460a01c1615612d07565b503461064c57604036600319011261064c57612d74613073565b602435612d8081613692565b33151580612e40575b80612e16575b612de65781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d8f565b50336001600160a01b0382161415612d89565b503461064c57602036600319011261064c57602061208d6004356131fc565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f2d575b602095868610811461148257858852879493929187908215611460575050600114612ed35750506113f2925003836131a8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f155750506113f2935082010138806113e4565b80548389018501528794508693909201918101612efd565b93607f1693612ea0565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613001575b8115612fd7575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd0565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fc9565b60005b83811061303e5750506000910152565b818101518382015260200161302e565b906020916130678151809281855285808601910161302b565b601f01601f1916010190565b600435906001600160a01b038216820361126757565b602435906001600160a01b038216820361126757565b6060906003190112611267576001600160a01b0390600435828116810361126757916024359081168103611267579060443590565b9181601f840112156112675782359167ffffffffffffffff8311611267576020808501948460051b01011161126757565b67ffffffffffffffff811161293a57604052565b610100810190811067ffffffffffffffff82111761293a57604052565b6060810190811067ffffffffffffffff82111761293a57604052565b610180810190811067ffffffffffffffff82111761293a57604052565b610140810190811067ffffffffffffffff82111761293a57604052565b6040810190811067ffffffffffffffff82111761293a57604052565b90601f8019910116810190811067ffffffffffffffff82111761293a57604052565b67ffffffffffffffff811161293a57601f01601f191660200190565b604435906001600160801b038216820361126757565b61320581613692565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348057600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613476575b508061346e575b6134575786855260038152828486205416948733151593846133a7575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761336f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133415750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339082600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132dd565b91929380915090613416575b156133c157908783926132b4565b8488876133de576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b50338614801561343b575b806133b357508782526005835233848684205416146133b3565b5085825260068352848220338352835260ff8583205416613421565b602487855190630da9b01360e01b82526004820152fd5b506001613297565b9050151538613290565b6024604051633250574960e11b815260006004820152fd5b91908110156134a85760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134cb82613136565b60006040838281528260208201520152565b906040516134ea81613136565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112675790565b919061353282828561324f565b803b61353f575b50505050565b61359b6001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061304e565b03906020816000938185885af190829082613631575b50506135e857826135c061407c565b80519190826135e15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613619575038808080613539565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368a575b8161364e602093836131a8565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b1565b3d9150613641565b8060005260036020526001600160a01b0360406000205416908115612852575090565b600090808252600a60205264ffffffffff918260408220541642106137675760096020526040812092835490808260c81c169182421015613751576137069394955060a01c168091039042036142f6565b9082815260096020526001600160801b039261372c8460026040852001541680946143d6565b9283116137395750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613794575050600490565b805460f81c6137ed575460a01c64ffffffffff1642106137e7576137b7816136b5565b9060005260096020526001600160801b0380600260406000200154169116106000146137e257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c1615908161392f575b5080613924575b61390d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138d5575b1692836138bf575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b838752600488528087206001815401905561389b565b6138f686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613893565b602486885190630da9b01360e01b82526004820152fd5b508181161515613832565b905015153861382b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139da575b505082156139c857505090565b9091506139d533926131fc565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139bb565b90613a1f6001600160801b03604084015116602060e08501510151906141ae565b916001600160801b0383511660c082015190156140525764ffffffffff815116156140285764ffffffffff81511690604081019164ffffffffff8351169081811015613fe8575050602081019064ffffffffff8251169081151580613fd6575b613f9557505064ffffffffff90511664ffffffffff8251169081811015613f5557505064ffffffffff8042169151169081811015613f15575050600754926001600160801b0381511660405190613ad582613136565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b378861316f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d2f84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613ef7575b50600184016007556001600160a01b03602083015116801561348057613d7f856001600160a01b03926137f4565b16613ec657613daa6001600160a01b036060840151166001600160801b038351169030903390614287565b6001600160801b0360208201511680613e97575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e8e6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec0906001600160a01b036060850151166001600160a01b0360e08601515116903390614287565b38613dbe565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d51565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a7f565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140a7573d9061408d826131ca565b9161409b60405193846131a8565b82523d6000602084013e565b606090565b6140d4906140b981614133565b90600052600960205260026040600020015460801c90613220565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141319161412c6064836131a8565b614485565b565b80600052600960205261414c60026040600020016134dd565b816000526009602052604060002060ff600182015460a01c1660001461417f57506001600160801b039150602001511690565b5460f81c61419157506140d4906136b5565b6140d491506001600160801b036040818351169201511690613220565b919091604051906141be8261318c565b600091828152826020820152936001600160801b03928383169182156142685767016345785d8a000080821161423157506141fa8591846143d6565b166020870192818452111561421d5750908261421892511690613220565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061427c8261318c565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293a5761413192604052614485565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b2578285101561437657908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c0570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447457670de0b6b3a7640000908183101561443d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b0600080836020829551910182875af16144a961407c565b9084614521565b9081519182151592836144f9575b5050506144c85750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144be565b90614560575080511561453657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145ab575b614571575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456956fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c034620003dc576001600160401b0390601f601f1962004dff3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149fd908162000402823960805181613dda015260a051818181612eb80152613e800152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613dd0565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f896145ad565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610343916145d8565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a8861473d565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614514565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b91610749816145ad565b92610752613dd0565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f896145ad565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b8576108936020916145ad565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613dd0565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b62866145ad565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c8b565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613dd0565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a6145ad565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c6145d8565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d3381868861473d565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a614514565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613c04565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613c04565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613dd0565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613e2c565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613c04565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613dd0565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613dd0565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b858861473d565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613dd0565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613c04565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613dd0565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613dd0565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b856145ad565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c6145d8565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b038416858361473d565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061271785614514565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614797565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613c04565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613dd0565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a082614514565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613dd0565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c848761473d565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613dd0565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613c04565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc61457d565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613b166040822061386e565b9185856020613b2486613ad1565b5101511611613bfb5781526009602052604081208585825460c81c161115613be557506001600160801b039485613b5a84613ad1565b5151169583519260019360011015613bd15750949392919084602060408501510151169581866001985b161115613b95575050505050505090565b909181879881613ba98798999a8598613ade565b5151160116970191868087613bbe8689613ade565b5101511697829392919796959498613b84565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613c2b575050600490565b805460f81c613c84575460a01c64ffffffffff164210613c7e57613c4e81613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c7957600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613dc6575b5080613dbb575b613da4579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d6c575b169283613d56575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d32565b613d8d86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d2a565b602486885190630da9b01360e01b82526004820152fd5b508181161515613cc9565b9050151538613cc2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e0257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e4e6001600160801b0360408401511660206101008501510151906145f3565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144ea5780156144c05781518015614496577f00000000000000000000000000000000000000000000000000000000000000008111614465575064ffffffffff6020613eb784613ad1565b5101511681101561440e5750600090819082815184905b80821061437d575050505064ffffffffff421664ffffffffff821681101561433d5750506001600160801b0316808203614306575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406a8951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b818110614261575050600185016007556001600160a01b03602083015116801561378d576140b7866001600160a01b0392613c8b565b16614230576140e26001600160a01b036060840151166001600160801b0383511690309033906146cc565b6001600160801b0360208201511680614200575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141f56141d660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a61417f8c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61422a906001600160a01b036060850151166001600160a01b0361010086015151169033906146cc565b386140f6565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a60205260406000209061427e8160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614081565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143a1906001600160801b036143988588613ade565b515116906145d8565b9364ffffffffff8060206143b58685613ade565b510151169416808511156143d157506001849301909291613ece565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061441f84613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614559575b5050821561454757505090565b9091506145543392613509565b161490565b60ff929450906040918152600660205281812033825260205220541691388061453a565b3d156145a8573d9061458e826134d9565b9161459c60405193846134b7565b82523d6000602084013e565b606090565b6145d5906145ba81614797565b90600052600960205260026040600020015460801c9061352d565b90565b9190916001600160801b038080941691160191821161354657565b919091604051906146038261349b565b600091828152826020820152936001600160801b03928383169182156146ad5767016345785d8a0000808211614676575061463f8591846148ae565b16602087019281845211156146625750908261465d9251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146c18261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761473b92604052614812565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261473b916147926064836134b7565b614812565b8060005260096020526147b060026040600020016138ec565b816000526009602052604060002060ff600182015460a01c166000146147e357506001600160801b039150602001511690565b5460f81c6147f557506145d590613af2565b6145d591506001600160801b03604081835116920151169061352d565b6001600160a01b03169061483d600080836020829551910182875af161483661457d565b908461495d565b908151918215159283614886575b5050506148555750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061484b565b9091906000198382098382029182808310920391808303921461494c57670de0b6b3a7640000908183101561491557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061499c575080511561497257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149e7575b6149ad575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149a556fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 8af9d3d97..c0b2c8a49 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -147,7 +147,11 @@ contract SablierV2LockupLinear is // {_createWithTimestamps} will nonetheless check that the end time is greater than the cliff time, // and also that the cliff time, if set, is greater than or equal to the start time. unchecked { - range.cliff = params.durations.cliff > 0 ? range.start + params.durations.cliff : 0; + // If the cliff duration is greater than zero, calculate the cliff time. + if (params.durations.cliff > 0) { + range.cliff = range.start + params.durations.cliff; + } + range.end = range.start + params.durations.total; } From 638b3b4ec5855a7775726a7d5ef022907b6995bc Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 20 Mar 2024 16:32:00 +0000 Subject: [PATCH 070/132] Integrate sphinx for deployment (#840) * build: integrate sphinx for deployment * build: bump sphinx * build: add runSphinx and runBroadcast in scripts * docs: use dev natspec tag * build: add sphinxProjectName * chore: add SPHINX_PROJECT_NAME in .env.example * docs: include SPHINX_PROJECT_NAME in constructor natspec --------- Co-authored-by: andreivladbrg --- .env.example | 4 +++ bun.lockb | Bin 43200 -> 306448 bytes foundry.toml | 12 +++++-- package.json | 1 + remappings.txt | 3 +- script/Base.s.sol | 32 ++++++++++++++--- script/DeployCore.s.sol | 30 +++++++++++++++- script/DeployCore2.s.sol | 34 +++++++++++++++++- script/DeployDeterministicCore.s.sol | 30 +++++++++++++++- script/DeployDeterministicCore2.s.sol | 34 +++++++++++++++++- script/DeployDeterministicLockupDynamic.s.sol | 26 +++++++++++++- script/DeployDeterministicLockupLinear.s.sol | 26 +++++++++++++- .../DeployDeterministicLockupTranched.s.sol | 26 +++++++++++++- script/DeployDeterministicNFTDescriptor.s.sol | 12 ++++++- script/DeployLockupDynamic.s.sol | 26 +++++++++++++- script/DeployLockupLinear.s.sol | 26 +++++++++++++- script/DeployLockupTranched.s.sol | 26 +++++++++++++- script/DeployNFTDescriptor.s.sol | 12 ++++++- 18 files changed, 339 insertions(+), 21 deletions(-) diff --git a/.env.example b/.env.example index 5c5efc6ee..5a6280118 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ export API_KEY_INFURA="YOUR_API_KEY_INFURA" +export EOA="YOUR_EOA_ADDRESS" export FOUNDRY_PROFILE="lite" export MNEMONIC="YOUR_MNEMONIC" export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET" +export SPHINX_API_KEY="YOUR_API_KEY" +export SPHINX_ORG_ID="YOUR_ORG_ID" +export SPHINX_PROJECT_NAME="YOUR_PROJECT_NAME" diff --git a/bun.lockb b/bun.lockb index d743b39cfd31130c1ae2f424cb898572ed6c4d90..572d055eee25cc72f6479c713dbdea7a2fafeb60 100755 GIT binary patch literal 306448 zcmeFa1yogA_ddK;Fc2(I?7$}ML?x6kQB>?Yz#){960k6^yAiwaVt03UcXy*=_kTX@ zH81D#D(nrv@s06~;TrewoHf^c=A3J;*lX_%-m+z?hJ^%Ib@vUZstpJ)?H(3jKp!i= zK#x9NzJ6LOufSk`O{i6PHG`~@Bpt}7SMTDR%^d=~Yi{m+?OVMPZN87&>r(Sh_L8qw z7Te|BGkT>SX-QI+Y{?+yl;K~D7WILjVU0^ZNs6YAl#4K$(3CJF(9g#=AXEwp)`o`q zYJ)dskt73>hicsYw4{?D>KDlnyi`}>}%CKM3RES0wO&EJ+*nVOOi3QeI%(nCCB#JCJ5M7=vr7Vz57*LVa5gSwmQ$j54d^8`*1*q0FF5Na+- zl)C67Ld>HZgy=`VkYuw`SeUOTzJ&#N`g-_EQZGw+K7@t@28WWodU<)=DqG3@D@FAJ z#6L)N#Ji0U^MUe^ydtMmk>d*W4@!1Ww5rVG^*(~yFgB%#5YU|;`W zjaSNiZC*{blX{+xtSG{2{^~udjdiN0OTm�jsR|kRqa6*Oi>`r=! zyGbK4kCS%|N%Hay@U#jGl1yym_FMvkaLLnzY6)ro4V7})%I&{#kO|VypHe4GJ8WOD4czXH<2mP`W{UAiXeM790x3Hb|a-Kqj+^Mmg4<9w#hBbf`PZAE%V^9uf}H<#lH z_LJ9@dq5RjW~Ip_$NX_>A+MLZgvs-RE~i1Ez8>{j%Im*8p)u(dCq#c~-}Qk7ciN^k z0iF`uyG{OZeF<}st>yN60y~i&#$yD<1@!le)fI z!~0$bs)N^(5cxhP{Byg;)88t}H%Lk#Is9;ZQ-oeetWVD8`8euh2 z&qhdFb@aJzl0?H7J&&*^p`WPN7j*-|sw8hqc1sfGBP>lgwyY%4r7${)5c1}P@Oz#R z?R<_~=P5~rsLuOK0<~A7I`(_d5I@O}>aa78_ImUqnh^cSOPd4oTaMc4(iOdi>acG~ zXFy}ZY$Pv3SWWcT-dE1^D^h~LmsHO~_<#_0Zjc<;Dc3%7ds#xv>$|<>^IZrTD@^s1 zRL8zpkJ^h6<|c&vGs)q1gTKt%Om+BaLz4q`r;{9ccu#foe}14WA5MttY@;Cg+~7}j zQ>sU5Ljvfl#QQq$^SpoK;Ec{G^X@{Xl3+cw68}LbR_Z#QCfh#R)rgsSf^ZLc|$E2>;=P=s#Ugg0yq0vfO#R?1!{Nef_nPKb-?MvKET3$q(kW*;IL+&LsqIi}3$wsocJr>d40wLiA(BGC3|yNMwLVAK%c0LZ5ChASg_}acZ|hmKULR#NW@y*TaYG(l!u*b$OTC5%-3bvR(}Nhn*!f&XD_x z^G&EvaA26X&mW)rq<$X6&w+v?l8=|tqg8U8*9j4am#=pi-BU>?s184LcN6TX4VCr_ zz0~_d>V1LFO&)X{rfx_h^Wb*#6!LY_RXxoHxOTYZ;|H(&zGaL?y)ZU z`W#I^{9ao&+jKB$A0*k>O~2^&ydfPJCDlp zvDEKUB=~r)07h7pabC%2NrAA1QpKmDT73&fEZ26ON zKYR$Wp80tLpYKzj+f$#@`TSm={NTC~MAvnUN2xRNJjL?>+9@S1)nPvuA?DeK)AIN~ zCd^Cq3xt>_M+uYXdtk7)CP0#wpA++)5OOU&g7ys#2~B<9Jyqycpg3Tswc( z#Ju49sQN-)fe`&HCdQYa{}ds)5y>?k9@-$fgWqyP_DhEcjUPP{<9Wy9%zSqbujKx? zhiH?Zk7XmfSa-A!`l6rM=gETP7Z`@eOVZ_AvL8<^JtEQe^*cdzjL%L&j3>>1-$3Zm zJVpKb9l0OJ1#Tfk{L!R?dEAZWH;~qDavtl9wEy;Y(s|1ole$S)%M?D*E_>59MfxSi zPOvK7bKUhHLvHq{)^@$cw()M)?pYKl)go$cpi}#E*8WpUnB6P8H<#JAE?MT>aQZYq z=!ajHwLxYM*H;Es-{_aB*4ZGadmz}4&RNcR*$ngUv z?tRNOvdf*f-nmW*XPdpB|7h{%VK<5ue$wni>uGuHZZ@~CXcT?8o5h$Bm2KQd*Uh8f zy=$=}n6;8Z1$*w(Ufuz-W(hlH0R363rREAUM@PI zOj52E1Gc?iT6gW<`{9k|)_1ws?NP^<;T`%HGl^UC=jxbF4do5Pls zcrmHJ~3x9L5 z@E(tvpPqMHlVy31Lq&tGe6T6vpt*eSeD(qNTw7XJ*s!=lnHnYmhBay~{H%3-;5yhL z*VeC<-rjy4V)|xFuL2{>ubvV$+^Fw_CPg2N`@G}(iu|^V9DJ!$2U z#Ez?3{`0BX`%j?-WBn_abWfP(-uhRqzAjByJkK|*O)j&DdHq%liMu;9$^7=WyhUDB zsXeP>y=vLUhfem>%=EUlak&`sz3GH&WAlDlyfSOnyor}O?7w~ZdE3Lsu42(5Ttu~BWYd_qj;X=1PgJ*reXWymg>YF=WmI<*e>QlSt zvZ|J^rbpc09x}%fZb}o-QAg_wwcJ zL66%+WozXYyXE%g6?r|{E?w~Qv-_={#yM-PDAQ@t*O*`BUKo}xl6z?R8kh6b4=7Nu zMYBKoE!JZ0yB)W3b{@B-bAgBVliYb8^L!m{d$CyavqznaCa#}cuewce#R>gPifI>Z z8J6^7Sx!s)>bZATn_9HpulfB)UTK!4-YB~x(}O+yZdt^|EDl^hYlgGI{PNM37BO1) z;hpMu4U-0m4jz&gz#w=-AtyBL`kBkSe z+Bsuui1UIr zx}er0izX)F#RtVjUh~Maa@cA2jlAB=*SuX|e#fOIKke<0^sKe)S@(enwL1?oH2dds zl;4L5Eqd~NJ#^yvra?Vh_DwxckBuLY$29Auh+&l?J}vGt(5=OR<(KN+4ZqFfys*T_ z=JWOrZO;BGRbP6h*we62!`5ognAdN;EuvPpLD5^v51r8YMQlVRtGHupY_@y0Z&><^ zk=dq#b_?FLirroJfx)=dx5gcwoZB#m)xBc--w*GTME^>QETM~PM{lvpwlwdV14%hYH_35l@uEh#mY;eW-TjT5 z*9PfP__LBn3YTo$)oe)RO|RV^_|0w*t36id*TO2E+S()ar&PMp;Kq$c-e)}rjO<-* z;*0wUb)yr%IV5FCdbB%q@55WJM|@wE=&{Ck#if(Ry9<5yJMg1b*NC2lD-PFOTu`Hp z+l80qq5|`E4*Y0-cEILU>v?_g{@Cr7uiuE8H8)*cVEf$u-uG^0ZdC12u}7IFOEw<7 zwCT#krkv-jQAV4`nB@!WyX=+}Ua^QzLfJ(-4bDX7%k$VbPti@TAxl0VfN>}cTD$U zwpF)poix-mCUMklvr;pQlrU>M)~(meUtcF_J`Tv+F@T63ucYD_z&sW<=uTzco zr?Mv;GOyb7`{%AENuR^M40n4mWz)hzH|jST7~EmYKNX&iKezv+^M||Pr5<-FX%yD< z36cPu&2(VnwMSXFa1(?$N9(Z%R@GfEPHv(zJ*H$^eg=I zXO$Kc!wx&Nb&U7gX4mVw{Jf1J-VPh2(aS%?uH2A-EY6z>oQdtz$Y;#gk=EUP8;&0L zp#T0j&wf98c;Lj7o|Q{QM2M#^=}(q^mg7eUbA<6ANDR=Vv~T1 z1_c}%ZJptnH~hx!gxcfowtc5v6e7L2?E7Y6&f?ocEUUWL*i=-1%%}zja!)IIp_*s$ zkaHTXWPWDw5%XCGOic_2mNGoyHP+Ov>ddMwp16eV>gij#Y1v}MHS=C;yW1Mx82)MF zB>#e&d%r!~X?wGYx3)I8_Pugh$+r8EY8~5E`cgV(>wRfbcfE$=7uy^;Ve(|)1&1b= zG)Wxqpr_ZGx*iEHbj8}-a?nYeS#|dBDSjiz*P&s@yL~RPJi_4ZzD`GigWqOo(DdD5Ztay2GPPol-rT--NxLJR6B=2ZeDSKrgy>goIli8OkE^XuxZTTX{;h;X zraL}&X=UtW+BawMC7wM8E@~OrPWxkpb&2|eKTN%_vee0*@ZZ{b~&qQ+Ty?e#n|XTaQ9mED$~ujh8W*Q_eHFW8>? zNKd@~!2gwQt)t_G-}J^1D|zZthBKqPbEqbk9P^;P$1Kb!ss5@D-=&7G00` z^c=Cd+4B7Xg=U*ZU94Qzpy9zox2%mfei?u5i*dKZohro_>eMp3@8TS0&ms>EJ5;&h z+xX+_ob?a>*ni9=r`g`)`3l!}oN{j1Oxa-5HtJ*WM`^T!r6 zTklc9?RbmP+vCd@^4Isizo+2om)&NBt<3r+q*E*NfC_sCj_~bmoZEhr%cGwqZ|91? zFlWbi>;2RHCa*jE`0dD_H^!Xx@f&7p^x^BJ_Ujr98na=_w2~%qZ>(;N802r-Fk;l; zr{|K6T+Oq}VC33v-DeMJX58Vzud6j4M8@u0&igv=^SpmwD_MB9W>t~v(eLXF&~LWk z)x-v6x5VElF^$g^FB;6RSmVUY7cEi~EWR;fhsAA=_+JUJ$rJ&PH;`|OO|*WOR>v^jTQ+a5{bUz^Nd`DV+g zNwGN})mxNj*0!+mJM0S2?;ksUdHWiditoMIZsWlvfw9A%E-AV9-j0apu2-FY*uF6| z?d@~^Ypa42BFg-{cIx(mSc5vHwvBsja&cUf-OEnA%I4N@%;OowKjyyQ;CYLwlZ~Eh zR_iwkU3N*T|2}+?^Vt6S1wywjh;y2qaH&(m;jwE+3|VrZz;(Ux4NdH8HxAo>=EjBR z{jNSJ+Imgl3Qx-1o;15`(}Rr)xdgj(ENilR?))p~UIy6>Sh06-gFMTVB1U$KEwiQn z;?~VIt55oDaaug*sAcWu5mpv22ACIpYJ7X(o(mrJ3zQw~RQcV@(k5$jU-yrQ*?b}R z=ZdeF?~f~Ar)88ymHDr$I7T*}yn~Nmp9|?4y^HOa|svyG28R%&AZ>TM)Bw#E_d5KbFF0m z%Jbo~kE8mxEbcTU{OQ%KrSjO#cwVf3yH0PSPqZXTgH5!XO+*t($_cDPgWkV_|nlz@7ABMT3!=o)~0Xp z+@>!#F7Ea`-j1)o3(6&w%X92U*RQrmUHTRud4%;0E1oFaeg4AI$2*nHUBpA*B_Z~F z-U_=nv@u;8>aT5h_Q#5`3r7q!`sBI9ZAn7xi7p<}(A~?AIt3qo)@dm7?}d9PSqOvu!Dd&mG&& zk$%4ZdVJEyr38kwY^JpRIR!iTUlZVa+NxxAwYsHFneRCi%LS=@V18>q|bT z^8R`C#f#H%x0+1m{e9K0p05Tv&R;sw;AUMT|A?yn*L9mRxc{ZZLko75wn)0rAg0^V zUPD?MJl`0%=gQ5;i)Z`0)G-_y(rQ%2XD3b#Gj27;{`{Q-bGj~zEKzj+vlTl^mvl3H z7NhMP7NVZkF9C5%Ho{e<1DvU#kp<`-gv@eLl0vUrx6um__~_7W>=XP(rc&G*DLM^U#GY~ zQ_c=@KWmfM^pxA|N_%>rv+~|oc6#`Yi)QbuR5JR$*z^08-YX8~mz>vC^Bcdm-1gZo zt`ssKzwmSA4UxUJH*ad=*&)h%i|_fdrA`iL^)g^ajxRUo)$wS(?x1(*qIJIvzC~Sb z@%BymJ&S7AImPFb3rjkCyf6H+squ$*>-E3I&gA=o;$`2RUQ)e-58E+~80O_a_uZ*V z)*I@DyLH>O*{!qbyGD6;Rn0PWW{(q^_XiFwdHdt=(tu*SjT*grKWM+z>X+_4hZLTA z?YfK4g94R@EvP+t)y6Z1gBArnom1WLbBJNq^;d(tE?dj{wo&}&7xz9FX&u90!F(fKi%T8elp81-%pIK3K?z&|!8`m*9 z>xW&9{E@>%|0i7%?(#*3`#=^J}_o_q}+q`oM{?&OS-S z5~{ZDXFk97xivpcA_f&Jx8Uxa)2p;K7F+EelkecFGY5Xm{L#pyZOb|_s}_t&syjEE zqsKmn<)dEKEN9WF-LE#;?2Ss=HH{wMx`x;H(|Wg^$~|6?BXD5n&Lw)ipISV~?M$a9 z9fJplcdSuj`~a8Z=R@}VywtW~t`j+*RcP*V{N!a9r}!5W@6}p5W8O>s(!K2Yxq;LA zefmRZZ_-rEvcxHBlTA{aL4G@LuG_Hkr2m9Zi(4l-Ew}7=yerc&=T^+4VlV#m+$Xi1p94*| zG}a$et>N4^W^If|ep!CNVq%=M%53_9Xy?+!uW!oLFR!s(u;Cu#rngIe3lA!Hv}U1c zoee`qhMr8lKcwCl_}uj1dRQx`N^xaIxqR2#xUaZj>T~g*&cn`4^FGgEn8#>Got`fW z4);FTde`!aHqV;fKR35c_T1O~YJ?pLk{&T+^RIjZu8M{dT}W73ghv7aVv zH+nLA@q+w3UwSNk^?6vAlJEKY%+KBSOq^k`#^U8@-nVw=pYTtOdHz>V^)FQGN%z)C zldA3-*Q&|Sa^0kV@_zX;aR~2YS3N^tndHBmYn97et1D(5-nOssCU2)Ur_ane80736 zJa&+O%Mw37RgQX)qx_AQ(;8Ht@~eU6qZN^zYV*EW=4Nq?VU8YQDlg2w&-bqXo45x_%|9B&MVZW>czM?FibD;SH9lbNb8qN*kMXB-cHh73^w8$t7rf2& zbJUh|iF31@^|`y=bj`4@MLTvLe5>y%zTa3rv#?3h5Px&#U$9%`_H9n>fAjNT`m$?sH$uF^Oik3tS9uXSTAPd*Xh=KBA2`m8qs>o`D+c`ruVtp|J3mL_bTMw6V<6^VtcRb4t-*;Tv>9U z?=PO+{qk~TV8x1O2N~?Be*a#+#yM^4IcgWVXEW`ZZ(`)g zaou0}q`vPy;GMfwW%q#FjzPx7jz8^St6#s)u{&MYL^02*`C-StRRT-qyL-d);<0g~ zI^0XFwaTf=^pKw4OHBGa%HF+m{E)SeC)SG_V5$G;z^8k4PCd1bU;Xq)_NQe|wlXkW z=T&yZl~;L(Wc{|cz{o?r0_X1VF5+<_%Qo|4w%1SY9u>E74T9E zY6s`rvnA~G$3{rZpP@k=jPoi%pk z=Rd<+=L~2#EVj$Vy*V77eAzlJSijHXr*@M*SIQE8wdjo{@jUN%oS7eWb63YB#c%b^ z5$5w`{psw#`p#OoVbHg7Ry_yD9BkC#vE75tElW2%;8-+&#Ph|b2MU#IzW!PR{r8(^ zAN@4*Ww~k_H&yN3)NRP9JeRZeEb{JR-j$8=Uzt)g?qGDG*nmS#?}Ya&y|qGr|N398 z&$rhLjJR5$NS)n}FYj<&KDQI^GX^eC8;BIgn#r&X}_3%iU{?Hk9tn=N#*LdRp#r{mxjcL z63c!|NF`)ld-_7J4WqMDJN&DSf0pnMK8jlYZNcaKtK}EXCP{W8|71#{s-gm2lmSHO zKzyYX8CaWQ^8f0f!`z6TNQh|hJk{Kdpa{P3?P2kejD2T6@} z{Hq;5YZ`d;A3S^zhmykn!-?-ieDLsLd3rWjZzu7q5+CD7?`0Ji=9i&~UrWco+Wxx{ zpVvR~ua-Za_%7t1<6%s%Bdm9W_-%-<)Gym*zC{i>{~Wv0ImG-y#7F)JBnm}wVg3#x zS`%Ll7fzV}f%v?CD|W8Kx1fmw{~2BXS|YN4`uza>E{UST@y8M0LF7*nQ7AG01@Y}f z{Fnnu=K=GZ(=SJW&-qu&A47ag;)4g9O7qD6FA`sO{;TzGM!&p)^_NlqU5H;r@GTY4Ny?`LV>e7yU;L>338V73M!A zKJWjKVGmbQm|vPU?Uuqncq~uP2J7`BzAf?j+Ck}5RG7b+_-%!MrE?Dsn4gmphU*WR zNgjWtHkf~#_;$osy6?g_3iC_mk@t^`^4*DVmkIxih~Jp_hzB3F{r@8TgO?G0eflLP z?B7^Fu%Xs}2=Ot0GrIq+A%1hwfB05A|GyC5MaMsxP*jjB6gT=MGza2i{FU|{Jm$v| zAL|e61~M8BMTPlg=%Uw{_)7OpHqLwx;v;^gc}vZYCw?`-#~e^U03De-asQd2noy!6X{&cx^IkJ|XXh!6j4Pc45n z@p=978dTB`_VEaGGSV*M!fjX0Tq zQ}Dr6I(KyWhIC*>{Op_ULMN@ldUnL;@q-PeW61o`#CIb9T<18_@{KmuzeRk9OvGQN z(0|8YX%5+cXTj&V)%Jff@v;9fKfQi)JNrLFeB>W|-oscYEo6Q!`sH5u$NU3dZTvyR zhkvDc!gLOTb_Oy8rNU+A2OwJFh7v^?!-quBkT7Z@%jD(e6~wp z(=4oKLcdsz{6iTsrSpLKZHezdeC+>}N{RPz`kH28{xag%5dBB)Se_`ISqgj34A`$3K+#$RA=?%7q{Hznb_Bh|l+}N^LOz8S$}x(SLAR4j*Y1)+<&r zW&dDVT0CxJ-JZn9{+H4G&m=z9AKO*i|4YQLE&Suzg<8HrDf#{#*FC<6=UCE0?teSt zWB-9Jk3m{IZe#vp;&&rH>PlmW4d(wMKF&{&<pOgyV86=2 z(lERH-lLmj?_UK-n;u1|e*V{% z_?Fav-v8A0e-QDpet7R!%Rf#0hQtRCHq@S94JxHPKOnm5{8Dget1ma`;=O6;EA8OaG<$NmEn_FlFA4QTVj`42pN*e-odv#?%M;$!|m8U0tge=H(?GvOa= z2RTqu*#8USR~7!jE2D%=I?OLiWZXY+-dLWV8P@YAKAztpZuFn!O8Ifbw-fR69*`av z?d<0U@%j9QHLSESKR*p#ec>PHFQtX~U5JnVqn?rZKY{p|KWcJ^7}@`BA~z*Ij~`=t z{a}9f>i@leWVuql9r2xofB4Rw9#OQjpUK4M^@}F8@t-0-@&{f<=Fbn}{NC-FJ|*h5&Jo(?)@pGbUr;+u#*DUE~qRq618@yjRpY(G6@{!rrU=1=Jviuvn_ zkNY>&F@8$Nkon(TuM3NyU^qll0FgRfg^^S_Ds7=Pxc7dN+ae_se?IZ)7Wm)!t8@=!{t4n^{CVE0^{-Ed5A+}NPAONn{~d{s{6m%zemwEf ze{i`^u$5k6-3!FW{TKH?Js!6+zZ7+z`_FAkkonyOAL~a=VSXI(v43PV{tLuM|9Sl= zje-4}(8ELYAH0l=Ut8j1{4syj6!yP}_`3VQQX9-aPkij3@Q)lQjf44mcK=;}EKe^E z)~iN*-v2R%YS-^X!G}F?)$)%BK6q;8AjhB6Ufw_0ztTCt{Kmw0p!_S1o5D;k%pXB~ z%wHZirFNKqnE12>{=0vwjX!JSl=GufE;_*eI})GIA1sr5nD$TBT}XVaKg=EYXL;J} z6umpdr(3Xp^RJd)qKTY8K0heU0sHYLKE|K-FSY!Q#Lvw6C6V~N{@^=XdWjS59DfB0 z9`Q3*ZT!87jPcVWyWpzjFDE{J{{dlDpbzH}^|T7dpD6ru9dRfrtZ(V~-}$4KKbH7T z6hHEg{fF(Q7X$0PB0hB?Isf3WTq(agIcL7ovDfvpMexyYrS~4X{BMHKaWg87-_}{a zf5N=MyAQSb57yxu6JKc#IL@WS$NGa`aMjMgJH*HO%RyWewe!C$Jv_D}K65!P)YB@g z=Rth!d!jhka*{|||e z`G>fX1EuSb`K~P`sf&((rExHS1@ZCxfO(7@=bw=IUx<(Wk9mxL;<23hHR~FQxvQ5uf)jtbMiqhY_E;keolI zz7ZSi8nl;xe*}5s58Bf!%y%I^zkdf`?fQ!$KJH(^Wt-{wMmy{7O%=ad|6ho2FZ^Tg zLL5p8`?q#WS^to!<%bfV&)?Vs)bdvnpYK1E#LYS!|9#;f^H=HIgAL{v?T~VQMeHnx zPFjWadJ~`TUzGM8cA3AN`276CL`R;MZ(aTa;`8+rHkHP}{!4U}_b=YJ)bcwM-%jj5 zu)%f_V_JpvVu{cFFGvKABP}l4n17M@b;&;^X?s zYnS^4TWJ;6%h^RfKR_4b&+@dmXk)#G#K-)@xMd{&{W8g4PkefXlVSf-*Ua&4iI4S@ z(f)@MzkVk8Ylu((MPp1dvi{z5r~fx_Ciosb=>L(L3I0vu_sayoUC+$2WEm_Ta!8eYl)v3|5onw|Dw-C{ELWBN7#R#|6&hPQh5LQKzzD{Me}`+ zT7E|l`Zr*R&(|Hb{FTH<{2Ar{B0knH`(;co2i*TIo^tzOp-RD75kGrlyIlVhvYxB2{QRBuFosGB z^J9sR^CRa?E&nU=9Yy?DyK4Eiz2*7GJf&m6@kbJ$eg!Kz|CoPD3-i7E$nonFF(dqy z#BY)b|F4PPEED{CewpJBA-;Vk{O>1zi%js1{4*DS2jcVjJtO0Hl=zt$zuWvsw9opt=H zjsFGlYY-p(`lZlV`a|&l_ z`3H!P^9OirLzqevIQ}fbl4M7G)bYVMDk;pjCqB+!IKQfyzxJ@wxiU42jb)W39iy>KWwv~NyNwg4}Kx~sLh`ZJv_km3w(U?&__vO z|FekiB>3R5JUtt%cboXUe!x+h1LhZxkl+6yb`(ar_UE6>Z%O>dB7Vr!=5GS=dHmo_ zZTv@xUyuAVS1lh8k2rsbU+Ese{kI{$Zv1NbV~Nk}4>r~2{}u5&Wn%s~M*a8SZ$=)K z6z>0I;le1!F8lct zvYyGH|IUB4=Z9Xzchu>>(VrZqlC%G%#P6V!f0n0G|DP)BeM`kxx(=A{I{3f+XZim) zOeJ8wxy0|L6TjN|_l5X8e_&H>{7s@$#-Hb4s!)Gh<@kpXUw8jh8~-)pw-x<|O{Hg8 z_HQxdzx$8c>sMdm!HxEwv%2QtT%!9 zh@b0>O8GB|&(|+-)#kt9u#~?)NB-3Ie-QB<#rR?GP&x+O&jZA7DER0z%ke#}!g{}m zuY3K?mKI5;jrr|{%hwOCtL4WLAJ<>zshz*~h~HSJ|7zE7)fh>#)8VTfzd+*a=AZka zld9i-<$SFmzHa_m{#%lckoA5MpRXU7JGhTkQkd^HB4z)9Ozr&phxiVe$lojCw(}8u`b*!7?Q#Sa%5V8xdcrU$)Ksqr}JlgZS}bIqUriSx;}QoIkGrNk6rm z^_vjC3i(I>;a_e3rxPFN2j(%R_LsWO{!b8}&p*)NaZIhBy3YJ;{l(nHt`*F z;!o}8Pj&VmNqjrvqmH%D@;~ud&U)L3kMYO+=RUAbTFCrt%5O`2>>s@Tum>n9 z?0*vRG5(l8h@a)@*3Grz<{nGfG;3iJCAza{zS`J*;}TZoVSmwmGx zuKx+y{}bZZCO)p8x#^?Ue~U@-{K5XMCI{@lAMtC5{43pi&?n~qL;MEBPtA4LhH9!% z$E+TdZFp(rg%{xH7Un+`eDoW+W4W&G@4mBMsmZc`@LBdd{nRqn?LvHvKlldpQJeo| z#K-vMBQA2FbPU-44dT-~m*n|Zj`&Io^9xK#S-;3%3xx)l-*jrq`7j32K5$br(r{A_V4 zqad}dBJ&XA%*AI-L(!%_%#J3au zSGsq@2lL|uA9bZ?S6%)M;^Y1mzQI>J|8gvlpZ~(Y(zQpb|Hj{n_}Kp-%gFeRCVnF^ ze(+xwh7=Ue-{A%F_=8(Z0gqLf|AY80B0koy8sD(N{9cPv{{FB48&`nLpHF-{o%mUvo(a~wL;MEBhkhRV@Hn8JR$+e8 z#hJ^0TjEy}{*gnaXVa)GId|G$O@$2ctMPJh_%wJCY+Jdk2+6TkTe@1-lKj?S1G(G;ek@@A9W^Vp! ziO=^>=)cm!{udL!F~yI0k3ImE6z0DsKKjpfC0yvRzQr>6{D?a8r!-gh&v|faTI0oG~|MZ=8%dSW{zyC@1cXHqW!?_{jM zm-vl|ue9H6i}_hs$$ZrL8pt|nA@d!Gue*QbOpBz`#{4nF$NIzGuVxN1Kau#@|4>H` z)cP;CI&<^Cm*DgMr*{3#A-_36{IR9h(@!@rxo&n}xCqD0=JO=4;(awC6wJGOE$kqC9OMISx;43Zce-!bt zevp5qxrYztpBDZhQyRN2UvFJX{$NvS4D8>A_{{}iTHT=`W=ku@9zU%tWxoUFF>wAL5+CPR)LEt^4%RKSQU3jBUVBPoV16&+ z^YssYm5w3vXAvLc&vhlSLx=TG5+CEI^xVbvnQyQuW&D)JuIs-s@%i}y=a7A*h3tP2 z@ex1j@UJum=IU2v zub=2Y%hNN&dfB$f&yQH2^B*R2`dqX5>_BgR{G5k_8(7r*ne<#$NXpcZz%r}vEIY&nfv!6tafDX z-+u_oB!2_(TkG`yKb=gY!u`*>Gv)f7hWh_BF~1J+n`FX&B=K!C!QYxm|KEsjp9%jB zcV&)0koeA-@PCl_&2;!YF8?!NsRXQNv|E0Eh_!;p;)^KJIX|9%}cK_N6?3LHsPIuW1(68%O+_2UXBBj4Wn58GOt=e3TUC_aHvUZ$w0;W5E2$#P3G& zWBlM7^FT>qe$_)M=U2$o`u8P1_AmHW%0+zae-rU3@6i}HmZ3ep!n!Yne>J{goB4GQ z%lkk4V-B+%I%yTw>qC6RpHcq{iSH!%u*r7Q@{Kmu(?25r{t5D*i-qZtb@;7`uY3Qd z)CB7dAwGWp0d+isQCgV4llToY(f?}t;t-^X)PyF}(pXF(B(Z+g?#JADOUwS-lXZ|qZpRXG% zXT3im>+K*u&adD@#_~V$Sk8K{iI4noUG4Z+Ihk_*pOO5B65o#evtP~w$N4AZcsCNC z_a8hzP|JT!{QBe{^VgU@SOZE5`>%9L_McI{M<)66h+j7o@n0f-X8ND!w7h;Z+W%I> zZ%*-J-%~nv7$466OycADKm6147sZA7mCvMHf3S!1JWS6J^ZODX`DdPCdPLFA{N=>A z)8Q+m|J(nk#BWc0#E!x!*Z%yI{Wm--|NRv2AAe^2w}tuRi0_n%_|FsHh4`?C9C9B2 z>+OGQ?7#FmdH+TH8JRylh+kX8Z}7iv{wQJp>xs|j7bvs*k3`YHdWj-_)H4#l<@uEB zS4Q&ZNqpV&AI`u^3dcW#_?BY)l<-)G`TL2F{Bd3F`2Qq6<`33CK1vJw>vlmt|Det? zB{o=h3Gs3LM?E9^$9>{s{{XjuiWu1chKut3H;+Bb)9VB4Js>{f=e#p2<(IjXvi~9f z=!25N{ym7#=ckO!|AoZ27xCv+;#lag|NF$RPJD=!#tvQP8()?rJK-NPwfSpDd^|q^ zFC+7J81ZX}_;C&8xaez|h4nV+_|HiUwede9zV7@{I)?1O>=pU^$bMO#X7JR=dfka% zM<@U3@wlD&Q;E;-{}8*{_)ieuiu_~ja{|#}e?f)R++ht<@>?S_$pV_a{ zHO%p6zb@auA$Fzr{?KK-jfH=3)$)fBpXVReKK4K*h2!5xe5_w^F!pNqj~~K6)(yC7__1#AQ9FJQh|lv6T($fnxBol-YWLq3#BWUTbAK2qlr#(L zjVFFR(SO9QcK#nCz76rY-)i~U?xfs*vW+wY7mXZ$Gved?1TJJsZ7{z-@f!+0?jKn$ z-24$(?>X_g{~6&|x|=z^7x5i35q|>las9*GSF?w3|C5N{jQB)P-hV3Li-N-Z2KQ2a ze+v6A;!s+UZ@%Z(MLY*AA&lrE_D3`NV2+d(?Lf@g3ZkxykXIIRAb92iEreVb5qnk9 zPJ2pnNef|*?p>1Y(i~1MzeDKNqz~-Zr4Q<~W|QkQcauw62>nL%L4WM%gWNZ!4+;?N zO;Dkti#QL{*&?~UH5#etBJ8*(OVdW!Z!7eG*yB2jx-LSmi;$;<(CaGnbP@7yLavJ# zcMW~e?k?JasCx+X6mnfe|Gb1;7h$iDkOMI;fugR9upcDkK-deW55^&kK4=f84~i~A z-j6=O2>PG^!RwC-6?>wgiv5kj6879*X7 z^r=N3x;;-W!2I-iELZR=)V+oU4;CVkORScE$X_Mi)5dL z90=YQQBMmopMDDcUxeA|qYtt`e9cZj;5Vm`1MxMNKm#HF9il0>Xa{0^^NKnUU-OAN z5b+cgbtMSZLi7Xi6&5^Q#C?S&$>Fz}Xjg*RC+Z6Qv=HmUn)HB;ggy{oZA2Z2ueJj1 zgj^RPvZo*DM-$Pmi;z1CIS^l+1Ud_B3L%x>A)1thZf`11rVAcWpxLag6^2%)!H$k!1_Xfw{oH#h_4ky9ftV-AAA=A^j)yp&#If3V9eI{6rDbf6@R^A3}(A zHcHgT6M{E`5b@3-gul6jC_v~h5p^KqizkHMav}d6qWvFgM;xn#{u+U61y2_%lioF< ze_QC?5qdz_yDQos2{{n*$D$5|zZZn)&s))+B=8*};{Pb>p9oQa7^iQ9;6n*^vk1&8 zFdHE#`l6nl5CsT-hC*&6>c)hySD29glZpu}DX+CPb+w z>a_&c6LKK*8j3m){b(f6M#zD%YexuC6Z!$3Ga>Yw3V915Z!PL=MSD9@??8z4(Ss27 zdJ!TIUWDj(A3~JhA^iAJJJ4U~=^{iyLJovpUqZ~+C{gb(Z~!67?-0C!)Q-8FZh?k` zXv#-FVAmLxKOpQD6zxFh7bb+gB0`=KgxzAoPH{r?tGuuWg#8Mlo)$u{BI&_iWx+Ei zM4VQlUWE_^2>q&}{yW68nK)4ul_DA-5B9U4*{9kn1AkjY*EU97Ve>qTPw) zu-}vr^=3j(7jd0$C)(Q!bRz_>qo{Wh*qIPT7h$)HkONWgD(bojc{kDCoe=BQUFfBS z=$}^T0a5oMgvd|GbrF92NnVn0EFt_%BE)%mJ|X(GkPzdtnh*sD`C3BQ-$01x_hPOG$bs0$@)AO1 zBIH2u3krErQ7<%Er^=%j-crk=189`9T2tE+@$BH@-^>LyOM14FV;+rJoK*%Q( zmLgm$3X(FCHR4o``Twm-6A!Ny0Axdw z{=Ns0^MLmOm=}2dj{?N`4A1{jfT;g{4T42aw+jV7~l)4E|KpNHlI`l6)|)iTd{=1H*zyfN---NC{O*u48vSeM zwv~Po^6_O-;B4}2vaG4ouwKsat6#z%o}HDo$KW=jx^L<;uaACWi*oullNt`a=UMT=E=~l|y|I74> z1Fl-?FKRi)Ja^oeF-PM^>{;>n@q~AYFK!x_+IqgqfU(jmQ{N8R=j8S-5Ko3UUY*xO zlAcG*kJAbJ2VE*t{ocm{ac!GAbZ@_6@Em9N@ik`$_4@T`oxubX+s0?|ySQeTOh(tb zFkpIoqba5%zr=q#noF-sr;7L;e71{cl3esW1{Z8p=4OI@AA`x>O>QJMi%i)5;>*I2 zF-yFsK3lkAO;p_?XY8hT*j~=`V$-|vf%!*x_S|!ROwN}HXSO+P*yP;)AsJ%3c$dmW zFX4Wh9_`P!asOyJxUFkc!;ZNN-#=b-Ug1hlH?)mAt#@&4H{%m^8?>w(UM}QVsgNHt zn$>7mXwRVM^&bCNdR|-I-k=~EV!QaA3@&KC6|wBtL-ZHVoZe)`5CpmF8F;L zZ0nt=yzI$~-D@ohbS?d3`Q>@zyB{d@xpC!V&BHCP`b@7p0KZ4F2BzAx4J&H&fjBZW3s{V;+;Jgz3P>&o;ozXo>9rYS)QF~Qhn)=!2NmF zPqb=PY=D2%m<=x`6f~H4&L-E3D{n_^c{=B|S-Vqt^>&2bs@bDJpIn#PYKA{0Lu?oC zFuCY0-#czlp;`}|3zo2{YjM``xWO#{CWky1o*uS-$L&7tI!)`EG-u+i?|1Hw>;A~{ zR=#Q0)eDyX(aXEu&R#Kb&CQ=5tWAd4F3y--^t^YpJkV`btNxJ_78kGgYeM5I(=K%# zZ*jTS^%tWzE~(x8=dSUg2IhIXjb8tz@a$^uEU(!Yt;Z#$0$*Xzu14`gWG1dU#GNP(a5no^5i`bIhOB=IFOEuipmFHqe~VFJbO$a_!~B zpW*e}pR2sPrtR#CJ@p;$)b@(CHVS%jIQQMjd1fB};WFUfyV7?KJLg(hzA_o&c=0Zn zi(cr<-8Xa3xV36+?aj_+4~i_UTY6ldvF*MMsroIh@8p5?!w)Pza_8>r8Xe}@4|bm4 z;>7TUW9qLM()ZQnM%H@Sdq|dcWQgtJcNn z7*jk*ukMh9*Q3lwkB`4n|6R)lEyoSG-aYTi8%35}Jo~fNnJqh_^}YuEGuoL9v0dbZ zi{83oo2Jan^U3U$N51B}<1a*&YJO^RwFaS6j}3HgotV|9;r^#l?TUhH|)~geQf)AB`eMwX@6wEr?J=GnOdxTzv0Ln^D{kHT8ypmcI za{eyEcRPA)`moUDN#zcXo4)SE@9(i)>=j(}y8o!yIdSs3m-kIh?9MvB>zMMzX2|E<)i%e5tn0nWXbm4+xl1a-3F@?CYin;wl&tIdW#aS zGbUKAsGAVjBF~H+vm035+D?Ypt|=QO)EgW%>ErMk9~(svH{Da}QsYnEa?e`OI9Kbt zhR=@I%AWmkv1$$0wlHthsKjaKUN?UPx!Zgz;%jJD+GzQz4yWp7sWsr9j@`n#b_)zJ z9kDH_+p$K`E4Kak()aO+U%dzQ&+6bi&HrA@)jPYcb2YrPc4TPgAMfLzV2p1D3+*6;26f$twp4!gT= z*6yfP?G1WQ+FNN*#E!!Cqt|-e2^*{FGICUyUX!dx#!MaV^>UPs-J-g7@8obAeK~l= z)O{CDn_4<-bD28D!RXESpz>ur%53*v;&|fMgZA;)o=rM;bB=vL6>aeCiCNbSTWGm! zi?;oqm|o6SFLmtVZ@9SV)joB!^_-EXzO);-_3l63S#4%FFj}2y{fCLyLJr&lgjb@P+jo^--?AupvdC)NDV}{m&*51bS|2GZM0%02lmOHb{V+Yo5tr zkcfXhw|F$%( z9V-3J!js$hD+Cz_@Mnx50eTocRZOJ9A^e6MOxtel*z+wI-b46r#vbmaud{>&L4Yf( znu$htt5vqf>5G%l8x9s}&|t>sJ*<|MY2waG9&rAWL(ta@8gm;A%*$VgGU{&}iw`f% zBVesYC;x(&D4`iZ`^nVTFF+KZ&tbCBy?+hP;cHJ>pD#iUG6L~uIYXJfN!!B+!P zF9p!uhVss;5cJu{(UuH5B;xa`|Bq{TH!_ZvwSL}h_vEmx>Fx6D$jGVY4<@e>atrk8 zp;;D>=+q_c4aYaklUrQC=LIFuU47>-I~owX{;L%)+|HFjmql~E@gcAKs(ad7mTe(X z2$rOk7%Jm;Y4P8-sd!D1oj8m8(MJU2q|y>Q|A7up;5?%Ox-=$Nt#EE_+$~}K>fx~* zX!9ihc{`|k{AO7v{IvAxZUmX7?M&J*;9AjMN;3GIX;2%!@Y|0#?oUM+U$N;iYrubN z2^j}!p!;s?l6)`5bmk8Yk%aiguvUgi-(xoCRGGF&^IuGaiIJ{$dkkr3hl8CXa;@?V z%YKeJIn0H)<4FAZ8f5g3-FyI-2I%HLZ^sHb80GNa5Tv!Fk63UxUChA}(7zmsq}Xm+ zk)e~C>o$~Z_#XI0MjK32B`_{+&@m0vSy^KnE%L+^>(d`DH!Y@|8^?s+;k{=%pr2j`T2yRM0cdj zF|c`h6Wiv$YrD5_E-|~kwq16Qv@=2+!#@hl7(1^M5Rh)$0WNsXK>}pjH+@+_)$>i* zfma?aX@`TQr;>na(elK&0jX0UYQ+LJP|9p-c)%9=yKCNMprED?B0+F@m!LcRa}=$A zQO&zo2r?fSA?Rxc-4N&2_PcriwdYQ~KOaqeUz?rUA<`5psY5>-vX*Ai9B~@k4O1iS z8}XT+?}k(56V^w05hkc@>iw**Ze~H}!1=%gbVJq(FS&oxcaA369RV1%XG_FEWhtI9Cw=eC?iffyG3Y8lj-vobWbU{?AJ{` zeHh=#BAJ)dudfhf9GD^KYXvIMPvW_)sl_+qj+IF6OYWM*~w#i(g>@&9f`NvO*mB#P%kUc zP1pJ$>oVBJZ!x-r`w2&Jn9W!jg2)d z|32UOq8GZB-|3U50dU!Xu1?xQpGLO;!th$l4?E%DLF=5;yPw~&HG_mLh3V?X)GC8- zi2_gzBt)nzFQG6-^jVM3ipI9S=hVgs5Y4@_PXoB@KzF7>dfWK!IZlti1St!3pi{!_ zKTv|W{l6-+;N5*mbE!)aN7GGP#yHDt&hK+4UPPJ4hBWWtwvHrpSSn9ZNB;x396(q9 z#Ge^|QHZ^w>4}q;HcK!T&-|RidV)ebrInMuDzGu`t>eRj&#WW16Onr){T}M$fK+GR znx8kxkKcUO!Oe02mlNnVP9{g5=KtoRDrLFpi>2Z19{3?ujk3d-@s{(87z%=2isd(V zliR;YyqiKb;ao%h26(DIs&ImO|04Ap8@^`MpZ@61Tfx<}zwFkt>_YX6w5mWPWP{0xT7U+`WI z5+GZLhmiyUxUT!0G`*}ogkROgRtMmp%u z)xLd=!=fbXQZSEP$_MYYAubODea)aLrDUozIJDM_udD>=zd$J8UOWBdjXUTy+ zFJYA?20Z_%x^HpmH{K5=NOuTqO(s_b`Sm`-PJniJ*(bp7kPsLAJrIxpO^VI^`2e?# z9iJ=5;fv;g9p!TQ1^LlY`(w)BTi5JMIFk~QTX3Xtq2)B&`$O%1gV!Fg1%;uS3D-!nv$t9>}37RcN4}{-VXGi z$?z*8RNc{q=SfuCjdYiO2`=k#^XpSltOW1xxdm+Q=XI6US=gc9u#cgX0$c&0n~x(K z`^66<F9$nxVc1jSyG3q!n`g zlYE0C{o!+ukIiIfA?D7yz4s@ZG^-oOBC3yM@~;qN9Kd@-NPs*$I(9i?vPKzkE_GqPVG!^ODKI;c2)> zg1EvE^fiMP9f-)a3{SVUNAEfmrL0@4zI=6CErhdGUNf$I?nq^(Z+X$CT)L~8kG-H9RZdAnu}Y8CmjMLFy(a{{+p9qK$wJnX4*T0Zw8N{0#pP_X3&ua_?8AIGCw_ zE&x{y=x(o`HXP{?Y3YBkn+b2>$AU3h{LSKaILog=!c2~GWJa?1&SPT~z57-Ps*!JA zE${mw+I$Cd_Y!=~+U)7fCb;(k8DDXrt89FFVU}u>RGzKOj4cq*H(j*D%CL?O)_j*JkKP_oNe!Gk^>3c|iiyo2gefXETr- z{+3dPBJt{tOlpx490R!sHkm%{yC12=O1(;IK^0qD!V0u-@T7@HLY(hE+orM{Fv)OO z!Y@=wy+V+BB_Zf*23?Vmiaz^E-ff#BPmk`fg+raL=}x_2>8Mg%%m-~9M)>b3i1@(Mxf1-}DA z0#r3@i^&)JHe7lcj?49VUGea8fRgF!7tF;1Q?>*y$plGPlBWZf9jBU$-cWB`#7Zx+ zf@xFpfJfJBrpt_^1K|2A13_OiC~+~|Kc-PK>8%(6@h6E;W!M;7cg;aJJxon3%jh>a zVk|ZaKju}VNAF3dZo`IuwOY?{3Z^*C`_b)B4PvyqKfW4}dci#;NPtp;OP;vwJtLmG zJA*rnI#qV*j@^}F@0VXjeT?NOlw=leN>mjMHEXiY&aW^8qu3jI#J8Fm#BK~_zrb{y zOgXRQ? ziCl6wAYNG0*H-$#ePi6Xs6^t}O^jW*$soS0Ki--4J&)A@K@}$$`(4GGR|w*Q_u!BK z{SN-2c8bMr+!nkpmez2>6qR10a{8U(j}x|}#gXiEVaGjP%2vIYtq)W-(U&HYsLDiJ z0}!Do3=IVZ(zkE?;57l_DniiL3`%$$wDlD=({3^libB4b=653{_d4P$vo6MSoM1nk zOe7dbp{5_!`&AX3i676oHmDE?=P|0ogxl;Innr>AqX*zB{V#Vt?72gzEQ%F(2oJIC z$hW7rQefbmKBWdFO#83Y$p(*sUwUcg+52e&U!2UbOFdb?drE{q959grV^e4~f#AI$ zq+Vs9%Xi8^W~*>mL1FcY#O_S4iG7NyR5STXFlxYhKb;5{>e9^W$*e}Aa^WEz>RAupT9YcX3s zBWC@^liWpb{J`a8!fDM+Me)WL3tJ0`Y*`}KDniB5cv!g(;DXO|AOVUS^n7qso9J~H z)nI;{m{k9FK&+oe9OaF6B6GO+RmvPB6L|E~-;t0{mN_8e{^x^{9!6)5dg`05Ov~us zIh){~FQi^I2>O~q{u~*XMM|if{~D6YZ(cgfBz!oLNK(p`bozHP&F_kn zYF21bO_#gCKCK4O9isR&N_g-TNAH)L>t$2-YY8t;xI8(?UcYOpT1t}XKT09G6&`}G zd`pM_agjhLs!2*9>8=gkaS-6OnBD17tODxQ1iGg)vOIP_a449UW9^Zfi_1&)*Rx7u z_SbLa!w!*g`(pmR>B{>gX5u0(SR9*ITRK-=u+tYhfyZ28FjuND{j?2mwSexFuz=#& zmwW+O!=BETrp9C5K&6E>`k)bu)b?P)fo(bomXCahPHOd)NAN}lc`PdE?6%*>iFOnA zh-t@*cv2?;F1QB@2@o>$U7dEvL30T)L%g~boG82?+nP6uTUC7J_Li-?^KI*~txZHW2@jJs^{pj`xc@5zxo$cT^fiMxes%gS+fpyF;YDieOifmB zo#N>dMD9P~mVAa@VW}uF#4%OVHR|Mn3RS@0Md}K}#ytAlme#H8{84?URZT-ph@!N_>*!5;WQ3KGepMv0JK~-Eh5Zai7*( z#j4si8>Zb!XMIjQt}xT>TIPmO-RQuuFF zw2j5~7ie`>NExY&jqCD~@CVU)h!$_ZKD^Z?`W_pQly%l4=_@J!A9v}M9k^Ey8D9gS zt0hc8RYD*=zjYZE-uETSA-tiJ_66qB33VyW- ze)RSq%XWD9aV|#>#Q@h3=!#!pH*8elOf%ykz+8~mnys6d+N&2MMlAOS9kcaZtgjXI zK*QWP|6H3SL<@PQ7^3mVx}I8@x?*|r0i}AufDqt<--RIoI=7zn^ib+EU1sN&^&l6f zXDGo4xz?wC7qt;U(ruu)dc642;lC?$;pKPaSemIhxR>mjZ>|*n&|t44O5M!h0oPw+ z2>O~qwmn%6!P!48b3M|LGA^M(m|IW&PxQP3o55)}Jk0PP+MiMDH*e+NdDnT6+HrDx zZEQkIpj|)j;~O$du2JZ`e>EWE3x4;31W0;T(^m(yKETOH#VCOS)28xGl=jGE zX*cf;71Pd;GTPkfSYGN?a#DYV+ce)rv_?$Y9ZOGBk}$<|DNOc&zFqJoHbkWAj-O#J8H#4nwORtEJi)V=LJ*oa_$@SiBNz57+XTo=#i z@e2)$>LJX(tirjxCs#t%%t((Pj}L*J9xMxBfz^>dfw4)L1nB zgiOB~(i$8mdXfKjjV(c3g;0yAtVE$TD#(&kFWz4EONQ-!n2}G+h& zIVG#XhH(_0nk^?!VOX@oGR;}d_vE`At$3n+tQO{7i<)UP-%IbaJ`SN8kkML9ZbmI97>l?$n zQ^r-8t1kbI&JC_7&i$42@9@1wXpH2B7C!gK7vOhk$T-*lT`UG9)f;X`uEozQw*LO) zK2-Jfg^reTTmGYe&lD0`&1nu0&etR`ll};nByr|`8c>3sd&7b%5YT0f!;AT#1l|)v zT<};!0%Yh_&V*UFA%LHtn|Ue!-;Ue?NsZFC)}LOC1ipbkF+Q3spLD2`4ZEda6lnx~ zIp4)tjH37mJNwyc=LBzEQW1QH1##^l=xYYW)6CT-$C*70!!(2L+8<1{OrE2s#tk`7D(R z;DgA4_k}&s9cb(&OOY^D(YR;=g%IVQeD=O@Ju~nur*h*O-;-vzl_D9{4s#WyBi=oB z60aQ0crm9WK{307MSq;+m%3{Lo^Lt;-DEt!Zj;D_4Fs#;-bSsDHeM#7NxvdEsO+@X z650sWSJSh|uilMYlVYb}aM+PyJf`=1qbmlcmss?&C0!F;kO9WQ5$FoVDEs>JiVln} zt64CmBl_SYqYYjFcV0_AvwlqnYW;}1s_lPbk<1KI2S+{4q-kt3;D z|1^FdVQ)0i^Yb>7revZ*+3Sn|+)n`a|Kdl;JOl3$Apu%pZBOnUQ*G(S5cR)dO=Drj zPfz@*HXFhiwd>jECgCvkn~F8Bp}Sf{aYR@Niuw15&X&2$Svvu1!1~`TrQO_D2;zQ* zp#Mi1;(~iJkN~BFKv{3X>o;{kuN2(;PY1*)_2MFpNMylJy%QE*{2mfIukMl>KLxAf6bTvph z{4LAdtOX-_w7mvd7Q!8A?UF(XBbIxYxS{x=yPL#s2YC_%eNXW(yRMf?by%F8Eh87d zt#1V53cqOy1iD{=ZcpW}7#eu*MQi_<^ZE*GVp!i~sNR08-ccLzmy z5!G>&H@lNo^Maq5=Tj`1a+3SK;cXEsrqmS)d1%Km=Wq5dkj5_>xom*z1$6gEtojT5 zH?cmmiiQ#oa3*ds1gT2v>{lHokp8|h3qf$6L}0TXu)&brgQ`v=n%yh;Ys1xtT(l}@ z$}MxW`RfGWdIMe8-ft!z`_rRxwjSHH!A@S7NSYFLc9qvFjS2(*q7=F`;+8|x2lz5< z4OzmDV=iS=MhgBIDy8|0_|991J|8duTpysj-`^o75HjQKb{d7Quwg=nUlkqhv0(+% zb209d-L`U#>0l2^Yw3akIm3_fa?o%Kl5{R1yyiS zl9s+b_F?4~w>&_^>K`B*Ikw}#{8^%dj%$k$Uz*g|N)#zVV)ge=F4|7<3pbt?znSk{ zIlrCXCcyOry5=i0-f=C_z2C9KA|nQg^0=ueYe87m@SJR-3XagVYN+4pJ3nzU_~RK0 zi@N6gm~75A{SfQCKX2|xto5VD8~lzAx!?SOZWq4hSfF6Zd+hdj@kTqXWJZ(1+Wqj8Npd=fd_Fz> zF!iQq zQzD?*1hcPtOqHxHK=_4Kad8dfoLJy@5y&_M0o|xod@V!GtCtTu&P>r2w@G=hB<{sL zmr{j3cYKv3M+D~i9(}>&lA)wV!Q=_-mh|6;7@&*c!wI072#r#fE`j^EV4zDetnBww zd3)x7O`YyvUGPOi+R~yx*-IO|^?#ktahU(!%2#VS%}&w1CC)}(>+#JSU|I>Yqfdon zZ41F1@LT}b2&wlQ&|SkTY$`Ky8JzM*G5Bolz?EiJp^ud+^WbFza~HIq0F8UgA%F-y z?-|g(_iIr!skHUyN@ox=Ct}FvKexm92;hD`1n7DgmGx6QCQ77`aG9Z1UmYHeo7zS9 z1x~r5V~e3tw4Ufo3>ZsYTCM~M<*?VV>B_&iGPxOIV42mgW?Oc;um!I*ka|Obt^+2f zKP8o@gJ?rTys$Ya@&|_IjUE;O3;MD=>mS4ciHaU|v1_;nmBznOW86|&2lM0_+}RHy zu^kc*5qc{O;In>+8wPaocAjY&yws^96clVJ$)C68zMQ;a#eL`WF6^%W>id+L5RM(Q zg0zL3%pLT?v(gWw5##V3^3f~;51$NDy64+Y0d6?ZyVxbkEf|&X5zO|z>@C63j3{VbE@78I1Uj&cP-Ln zqIC;R9W^@t#_fcTr?&(ZiPyGg_&1#Vk_cG_Eb@jPKhazgIV_4?NX#)BoQ*9ZjHKs8 z0oqLitF?g_xVHrvhe)7%Un=|XMo*)z`MA^Jx9zUjPXa46&$jI@eb&h>Ar0d5q~Rb|}RvzNZuKUti!=|^=>)Ja=T zUv>Y9?6`HOvxBiW_#fJ|`L6DD??9LPG&O=E`m&`gHD0QPJKeJ zX6-LJeaG4hO?)gHIPPHwNf7znx#}SexwSF#VizJ+xkK$2u?{ zn9Cj{{UhGgOI;RoS%ZCZ_uqd9UY@PrXh_ectU`SwT(=mbk0jpUy%)V&0=Th2SDlZr z=rB2{jv^MHQ?-%WB^mF%hyb2kL|cD|aRreJ?1Q`L*7Sq<;o(TB&|k~e#+0P=lJH}# zc3ggQ4m@X%Gk_Zhbg}+SBN1ad6y+fkIUT74^&*HkkpMzgY3Tvs&&c;!li9fc$U+85RcBI*Ro7cKpe zy>l5dt@xww$!Spgqsl5TM2KhzZ^riVsr6Fr!&8V}4ahho0bO*{_j9ghRW)*L-*w=k z>(h8%o)eQ1l;1_Gn!CcCUVFfne#S6q(0nA)gY*5cC@39z!O z`;y$<|J{Jc^dY*gZYkj62D&K_^fiMNUD-Ij^Y=b#%E?acXc44u+{iKFn95==w%~Pb zs_ljeWzF7K|A)kdgY*_R`^)XaclHs&9rDp%$nAM#`vVgQuLfisz&#E~fc%XNWoovl zI89VSh33qk<|MsEl4c){$C%wuwA0y2KfuYZRy(o^>;K(cMqv=J9J_>hI{1M#uOQua zl9&LayZ#D6+%yRKnnCI}F--JI*?Il$e@osM`k<`3kAu!iBeL}-roY^)GIx3x)%i3Q zp(p;$yC}Vk{7#cYh&`!KRFd^_HB&N#UDpk8(}8Y_&8kfv^185!yuQPP??g)exumB* z;cRe&rn$^sUG&u*0;w@ow6IoUssHrLmZWtC$HJHUXWU$QuKxlo41Vtb+zgJj(eD+ovlx+Eze zyyf-FFDJ4V_+p_a{^-19( zoC6Gw^+UkVcF24HKRX}+dS*P|T4fu7755F3`6+617;;A>JX;}l1oHi;av&qynA@oR zi_z7&&#D)@-!eK!@U8QTQ8rt(yUiDa)p*RJ(pL!L=0MQb3{nz%7-aoGfH+vNd@gNE zR|N&Vu>C+V9OLs|rODM|ep^D5i)eB;yWD6iP6|1B7`fa*`cd(#fqW+}Z$nh1cNM?| z_Y5Eb5-PETDcWRtBWov$g{jSvn&Tf>jrq0qqkiH(rewNG6!WU9f|1LY8rib2>>r`+ ztu43z5Lxtp8re>D_gjsG1AruSjbqcWS7MTU; zbvydXE=I9t_}3ub8BBkH^(039&}*Ai>C5?1HTB}{B#~|#vTQ!U1^)~Q5HpvkoV7@u z^xCvRi(cMOSsBVvc#Djs2;8UmhZ}p1u4Uc#-lO752Y13YG$uxOnLB+^EAcs_n8Q| z@4}$7?n}O;+jViI58jb8$taacVox4=j05|9g+Moas*NTr=~B0Gj0+yeydXUG!Fugc z(8@GpVcb^8h+0X(Zukc_SOBa^rJJ4(82aH&BMQ*?5#P- z-gZQj6i`ofuNGt+egfTV_R`Umejc{4Vw(>}0x*|3ZdHv;aDM(`2*V;%3HF~kKwLm>ew5^8h^Q?K2>&{wY(o+@1L z^Lj)HPpqt*k|Cj%EEMDUb0i>Yrm?+k^<)P}t;q_F*Wk@_@_YE&PDT;xH}NTOe_R4V zUo)u71urX>xYN5jjvHhZ9tJ&T=~b^|w4cRK^0yDkOWUy6@C+kzv8;pcCpX+rFU>Vs zL=m+#L`BPA4M@GY$5ZvE|Sm*Do*oWh|{OTKg92WX$-hD_=cLicY8)4*w`b z`TaWYQPI|{m+ho>JoytQHB})bqJ|*#3PI`x_og5Ll7$ufoBb$KTYuDuLdC9>l15ci-P_W%`S#Vx$uYg-|2ReY(5sK?|Yb-?&>ESdrGvs;9eZWt%RVj z8H5$zXVOsib5bF~*x*~n{gEgY|K0&(r96k#o8NFUUre9+^;Pv;-&C*s;bSX{k5YQO zWA^MO*SqUv{%xWs2njrAAuf1rg9Iq3W$54~YnZQ?_H~K2`$!mDp&1??lCb;I3Nx{I z=N;y`^eCG7NG4lKH#|;_2=Wt9YZ}I=Pn4=s4+g=EAp+M)@LmHFpr@rr)pv741x+KE zD)yT==f6FxhL~1&@-LuT+&0+co_oZQNlmg*bG!pJ`kuyZQH_|)mFZjkI9u@)#9ar8 zFkc}^y)_W@HG`g;CrfQWO1RLwgdh(~h6c@=k`ak)P+^kR&UVR6D2&`6PP{#T<}@}3DDc=KC3gR zUngNqwa5SL2OrVQ)7lE=xy3V;-o8cYnH&|T6$^I2Z70IvPDa#q&J9QYq8;AcXRP0L zzVP=Si*xTQ1Q~~V2>O~qTfYKt+!C<1IE zm~$^bQ(?sjg+RS`H9IEnx5m_C$Ac&Qg7}0n4{#fRZnIGe?Nr+UO(Yqsz9Kcuxg zy^B+iNii~Fmv>)nIL7^ zkN}+}YLKI=x#$pD%Pb$_z9py`X~fiSDIt5X4P{bT@MuA;tjYBa$p9@mdX}N9-TsMw--YiLg1Ai(^fiM_Z8t`U*;)U^*EXbjA89s;7_9rhWYg`E-mf~B zTqlfg4xd5EiL|w7yloocx1XeW*S&A_-?j`^iKo2?_sw5$&llo016`*w77Wprf1Y!N zVn#%|ECu1-Y?l&H-CW|{w8

?KH^FitAWmxCyK-MO%T+&XaW_NO!P<+;**erB+lz zci^55#0B?cAOX6i;1&VpCCvOLkK&;|_n@S+#&QqHMINB@7OXa?llO%!vU2arASjee z`ty$1uOt@3Bz3l}o%=}S=iybTnJ>_7g`lq)L}=fNi%Wy_{ftju?>+5hz9q~XKl*NY z;k#mL$5wm)j~}V)ce+flDBHLAp{=x~hB8rSyh3vGv0n{Hy=_2O_mIK= zm#WHp!QZ4f*wFR@p0qUD#qH-f#nsni8HC8#;yBRaIfImyQ5*)l!o;Kq*v15>+8SXF z+ln0Wuuh+W>m<0h3JDOpURCGx;B==+)BT{n#37MM(abJ8|7}1ArxZ(La*RW@yw)27 zT+NO!B-7s9BlZwV3F%;8M2i~=+2GN_DO%vZr2~S#X3%WPz{CM5s+lacKdn-|>MtRL z=$Wr|%?G!ubq(|EFqo)FtFw<^2gz4r+?An<2*YKcQG#JL6{}uO$usT-(SXlm@R=DT zK;HIJR9)58PR^Bg=Cv(WtPbDVxwc7&p*UJ8-|mo?4RhvHcL^gu%JfUhbIb?bE<#Op!|pO~2|;f( z`t90ITulw0Fr;g7m=#csF&w;SkUR)@0D{#aU_xw?V( z%3`M+u*qQdsYJ`cJ$hnSQ;-%W}-i!!%>P} z+oj%(=CfBX0lWKVB2+jN>xBm3g4Z@kfK15U}h}PT{FrtOugkv7v7>KO?3*2Y*LD1I>BCkQj`n`*q zG4R*w*{}Gk?dRq?P$9h~F`sxIMaV7RaTjIv{OvocnTvnVOi%|ZW==591&Uj(dh+JM zg`3t4u&)MW9QuJSM-qtFyx47lbMPuQr6W_#ct$dglC-BvVL)b7_aq_p4gy_?j=8+C z&1M5{kH4k0Hzwufv4&yE|2b!vWwskuG;>4uU%L|yeDqC?DpD5qd1Gq8ZLa98^sZ8> zh_{kP>w}LSz#Rg*9pUa_e_l2z6ZKDIA{VGb=vsY8Q%YE+v8?pNCz-j_Zh0**Y+a&o z+9H^OY2SRRr#=f7w(4XbXZZN(KTi6W$99xI^JJNAtc1|uHQILgXO*t8V?P2(P2r%v2_W&yb1Jr^WE@!m2k zmDng=?X~kV!*KG5`_8x@A5c@{oR{TnKzPvg*>tp>0)z}ak%|&+%YfT z$c@AAF=4B4V;Cum^lF&L;?QiVm!jBRT}5|#6xf%W1iI%_Q%1s{5^MVcg!<~*sLFo1 zOerp*pX@)ja}>xn`+Q+Xwzev{EXTNEPbZHTi(ZM+@>yt5uf29CPc$kXr);(y=((PSl7T1W}7HMY+0ocnhmh*b^co9PM>7%L>NIInMtaD`?md zd=iClzXojfG&9?`{R6nuKsW4G;c$=23ET1arpL3DJ7y0eTbxocGJTQJ%%foGjNBTG z)3{(>V9(~J@b#Ui=5=FW%vzbXrng46xhx#{0dXQ3+6xvGSd4D*sA?voa zwpOI{Nyl+OMaQKqT>2G)jPD!-ea)Z>y?31>6G*dud2ch1@zMLJygl&(2Ztj$M{1f? zPhZTFic_jZb{f(t50$=9%78`@n`&5tNTIa!16Kt}&GmrmB>0^b5+IcoL$0hPSRr@9 zs&{(CBevT4G7~I17(5@4NSt){mc!Af0$M%c;9$vlvolUHLX5p1`1LBWjcO|uQ$}Nx zvix5mNWBXX^fiN?HG3-`TC62xnpk^uznX_`ibbLhGo9vN*U504qxMW~>IsUX8@3T!95O0fU0fL zhyIvzEc+h}+@AUKVZW7nrc9gk`J$8*=IIx~`&EGjw2L{pJkA2rjJ z?kd&a(Z($#6T12eLEK*u^fiOfI!?R`RF8t!qMyUlo8gWI2(O$(f9| zA^8eH>Ro}LuNf4)TYtSmcZug%vbfcOrngbe^_KpmOr$gmkIc6Zdn4v6?(TXCL+5F; z{OYU|`7!hxaXLF+Ns)7hbpc^50wrKS3Opu|0MRI)dVHDqZpx!c@ojQX=&g4zsv)SD zB>nOcu?s%F-a||`j#O*iW&!GHnnvIuMat+)qyrNRD~x$8xpoOQw&p7Ysdo*6zGl$j zp8akcul{siwQI>=<`4~5l2QekNPjIw;X%9N;KP$MCl%LUuV0bm%BDsdco3K&A;Tl$ z_AgZg*DS187J=;@zye2+i^WYP21^jM%kC~I^p&uyqppy#roR!~nT5i@F2_Fk}Jon4(FmB(ONN_F(t zFo6np?YX0z&!OU19T4a5z4Un*lUE4hZbH!442t4qrn|xsZ?vIfp!aawGEOMuA`Iak z$D_`(35pKh{WPTk!jk{hOY$rCyD)6Bhp}Yi9|w^v;=ODx#Q3WS40?dO1$3dd$>pJb z6jADSKX=PG*E}X!tDJ_yg}T_A-~ZXZSp4s9oaEf1srKu-J<2a@hrZ0an=(!+eyJO# zSo?chRy}ZU7EDKCy`U?mWaXhf4Uf4^K~15mr(UGRz}wF|8gRn!r>= zYm)ABjA5{_!yQ@NOCmOdMc?0q5#RHk74WkM;_d+5;v-?aeI@k|jm(4ha1BnGdCp4r zy&1dj3(v^Ww#p_Y9#f?)pMU*QIQ{O58uQVIhc|*Tj$SyTGvB5md|4`~5a8|t-Q$GE zNRgC%3Z{i|;=mhrhg!B%d0zjMmM@_W))9Rj+eaZy@}k?@Pu`wQl=WOPFTXz2W^G2% zQk0fM^~x;^fqOcTdjA039ko1PIRUT!t0YFF1_5Jc4aN>~DIKoUdar&dk^7}1YwK>* zE@iIGe#MVK0%QufOWhd&9_k1fK!;B^T6l?Bwh4|Gd0 zaHvfDyDT3|4pqEi@OxaM^Flq1wWXf_uD~%QKZ~f3SJNWD*?u@k#%h}Hs9EutRwFZ- z_x*KfLPW+Q$q)o^4}dQ1w;Q{-43a`5(6Z;SNy$Mhoav9&<9ky?v*^7IHC&z%u|n(@ z^f%l!l8$%B{)OjMnhaKHssi4K`5Trd7f`_c8+dO736MkLfNJ`&P?;(n{u2Yu7k$Yq zUIMR`8`7fEBsI83XdH(36mBIh&__JxXE-e{D!q$swv$DDPk}^qFiYxep}@~S96`|6 z3`&N+7&O#c%p;$dDLH9I^z_#z?=iDKSgi;e7D_gx(ksG;;mP=_Y!=_J91{XJH$9_l zDhn#E_&rEbR6X^(vEbsJht#f%a2Cqei$2WB|G4F| zWi@A;o{aDYd-K1-E3&PowvYU)E=M2XO!LQ(*bQP@Cj@W)7fU z@MldR0m8U=C^JYIHk2=59LuER&is1x8#eubM?AM1F)TX4mfZhTEqp;jlD!yaJRFZ_ z0N-2K$foKaGdspLewbs;smm(_8HY0n`kFx@QaYE)+EH;v7j3X~_Obuqk_So|FuS2O zv^HX=p#BpUxsDejOm|rN$+Tee;UJI5DS}!fpD`szCFZ#D=M%CAzy+V_KmyeE^W+ya zb~2}FzB9g3g1C41_dlS6r|iF&OTOGX5;3jG3{uh0^^tLz6lgEQkLcraETwdz)LBOs z&`|}bv+dwBEJ(c<5cD;Jc-AU5Vem%shMRi^4uXo6OQ6@P;tYtHt6km?>Ph9GRf)nr z=f?;fp{43_%)5DIMrfO+E18i&A1~=bVXTRW0o+TV>*O%iu=~^W%Xh9H;o@J!lCMnL z(2)g}89z=g?m(TkkDj?-%+dVTxnEJ?i~0VK=aY72)r@+#O?CqYw;8=+^ew=>0=i`J zv1p^8<7Un#XXk?U^6}RRRtl*;$=;c^8y;bv&Z_(yf1q1k*k|;%1U)4$e7Hb>e|<+*IIiJjT?3XiZ6Ij#jKqKv;I z)Mm5f`A?}jqpvb~)>J<_B<|+5qSE=B5sK3R+#8_#A$A2ZSt^qt(+Snx_fCv+nvHAw zlb}HVc6wAXVN0fNaEU7;8Ir;#SyQ2s0QKsI+@sE1rZnjy$3MO8Ih_y`fcqEdmSY-I z#iqdM)h;Ia9vd$r%zCb?q&Sxk5gTPMFOEc#;!P&O&0sfKHs4^Ip&_EI?EYJS`k-Q( z10!iDGE+Vu4{*U_4GB<2uB)u~(|3N86^2+6=2$Ng`>4X$iMGm+Z9nWHIO&WjESEEq z{wS@?jp}9@%|kMG2YUNXbzL#zzQo+*vS@HG12WImYMNEbXLidJj0KHkTYQHFb|IZo?oI7GN3=Q%#k!g(!@4I_>Zyy(5*=?^-H z5@q{35tXRS(B7jt3S565fUaX~8$lE$YA|0<;O~1ip=50HZ%|Rr(3J|%A;tXU&j@AG z_QJ@fajJ6h{F>?(Ssh%x%l=VEcDf_So`kGHax{Q?{{y;Nh%0A~n{s78dcVE*^yNoh zFyZ5J|6J!D_)Tq^ZTV*XiVUA2e$&*dj4&cnU7WBRRbk)DSDkHPVg1Lj`P1LYs{xygW>-<*!Pl!)a879+uDo#2t0r&;4Dc*n=Num?)&lnOvhK z0(H9>oI3@IB66X?a|?3ao`9}~P6c;l6m1~qdeUrVdpxcno;dgSA*UTTRsq)25}E%@ zU-FSz%ZNVFl8`xUln(A)vfmQ=ppCR@Z0&waq>=3dxX(aWm4xYqX85S9P-e&}R_#yg zI_li;BFE=A>)e8}9jm@hOUpCTqv-xPhFu%12QK5zjD$ISo5490Db-9M8;kF;ldFi zNPJ9|))a9tVu7i#oT$@qYRxeT*X6zApc)l6_w?;3y_a`D_K?BFzw_@aXeP0-0y%31 zDC__i8t5X)FYqI`1u#mIBxzN^wPO)$zU40a(Y9oE%ekM4rZGUZrIyq8BL(GypO1bl z@BU+;-M-Y9NNs1a-tJ0X#BK1}2pI<$pj$TN(Q-C|FPG%PXdbEE%`EWlQ9-+jqA=nD zcla?O*85C}(yqM9-T)WFQlXWnVy%to&e8F1GfcMKONKy76a4N3abbb3{-a970k@`p z|LwEH$Qtdv-jcgt^^MgJEyZ_#99f?!uhymOXRlw5sHB(atbNICSXqcv3XS3(l?k{> z`Lyiq0WJvWhBZqZO8ic5F&9pLkvM+;hYKFz==BeRL(mh|JwcsUqfGpXFBS7}j{R`7 zC==_uc3dz=G)MQjsGeq5vPr5G;GP+zUO1pj9YW*yJLihUoZ-rSNaPq#Vk!MOAy!D7 zS)LMZ&&&Re2jSNVjxKiGxSxUq{}E#Mlab6u6E0(Z6Nyn_sPM691i0`(SAEtHN`&KW zZbj5xo&HWoHw#^l`~ulOQA&p^j4$Y0oo&uvC7+R>zs+JHDLbRq2OFcN&@aYZ3BLVm zd@jDu1-^G7^&$XWm0wN%qmiyDTm10coV@>_OU5FKUG@0F{pD^CGg2j&R%2Uf$E_() zQ26i|XWhS96yR<1;0Dhhz9gPJ-G!YS16)L)+mN4LD_*f9g2@M~T(eUZ?tdO7VU`*G zHqg$Cxi)4wcrMLQ8{R~)?y-((g;FcG_C*>`l2@CWzPGflOzA;3ifx}OTY>$`&s zQTT$Zwi7yx4qB%KJS_@7yq|k>S=!kiWZU(QBxFDvqtc&>E&09XgzhFrKH^W_cKD)! zca!E8s^GN|G7iW<*JT6R&r9_OrAW;fNrJ;;{HdgiSH2NwHi$k(jUCOa?R`AqQ6-&I z=m-t`GXkO_{rvW%Y0nw*zct02iT>Od3xJCPbo-|6hcrWoctz^Zy_7(a(UtMc>l;#m zjr9$NI;J(7{%(tJx&M|~ro@)sMz7DL`F~)2`iM$dM3=f+~%d&8-aYzq_iVv!Dp1P+xOg*v%9s zeCXvjq8I$q4OlgqUhZJgESxC!D; zor!6;IXO6t<-9XUjn4~6TVaK;Y{CQ(>oXd8*2Vf=!DEkyUw4-YP&) zx?GbD;9>w>u^xt9(ly^1L8$Begk*t1Fi9`DQo!|>#QVd++my=@P~ zgj|*vca-BO8`&!^ohcU_cQJh6e&{XGjbNd)Lu~x>v0OVWaFdj#tkuBif?-Y6Y4;sj zT=ZSX-NovW1sV_c|0C_LqPlFl$Klf{At2q|p>zpIOA6A`-3t=4gqJ-(dZ;+v`p3xS-|?~iudGha#O{`3nXSd2 zw`Dt4s*&|$$cPD-!G07r=+aAC?b5UunpJg1Fe`96)R)E0bAJ>v*^Rn-m|C43+0oAZ zx_W;9R2Gp_<<$rRh|2=nbKzE$IK9YvbNmjrGN`@ot zGvwp%usmMjO~g&Nw~WaEAz2Kvc?Ax_RRv_G~C)atZrU*IL93)!nrYux&*Uw%vXo>9=!-ajvtR zjuZ-YNlS#C_}XW?fy4sDiwC+SHOdF160*fkz8P+&CHNLEb4suAA-2f}77tbLC7E;J zzwnv&(Lu=U_dr{8L}cF2bUm{?b1a^0jW}9q?301{D16X;s0z}~uBb_%d7}GjdeUnl zqk@YpD)VPV65&^F6rx9?ym}9f-?v%!@LlXHR=2|Utvoy<6v0cL&WItKh}U=EbB6$Q zpPmA9{r7zBUg*z)C7(w>{n))sR=Reg{Dm$6BUX*=6&ba_Z#c2@5<%vyhQY!R8EU~G zlQYFC%^-Ya_LMsYj=Kp#cemYgTyWP&zom`1l`!(lfUx@y*9g1oDE_PMLry4mBq7eX zEV}V)CwSH_FW;$?gaVkCRe8giP1ZdeUCQ85BY^fL0$pJz46TTg29Tu9QHJw_EbGp1o9FXHh zAKG1VA^0J8zOz41joxW~kKXfQ`Z6Xm3iBYJ&Vn3Hb>$spVy#1^BA#9VxMZMvNTz^1 zbJv3U_wzN;d5r!m^4heRL_t&rBQo_Gk`)H$+#T;Hv{*Hf(a_NYlZu~Sc^MWOZ9Iaumn~J1bldt`xi~_iH~q!HTIx@bzd|t0Ty?$LXjZQ}+{gf9 z7I%D%k(o;Rs5^-rE^`}|Y`RoE$&d70K_FfV(1mMy!X|6bRC+B;`D5`*vhtOMUDH-) z6l`{KXKRSp$m08uEsK(VcQc85gf>d3iu$bl!>1IbQ5D_;sQxI&K3Tw}1l>1D>)}F+ z@-Z>BurA1@m5k@ZAqw{i5XJ=ocXwMk0=bylvz??R!P`rDXoU0de|%gkyHU4Z!y1 zkyBU$>9?hvD1;CiWlx*Fm`5)si{d}EVgEfRsX^C&n{w}!54L$i#q-v-F6(295A3E|y(+=bYcDe2@hz*H2nF2fW4ZOiRM;g$*Co+nz z$u{hriwx#amX>0-9x+V#-aO)mDt}Ou7bk`usZGB573It9LwdPzcG0l1H=-@=jHBIC zMRD;RZfoou5HBt0mg9%`J!iS3KPtPAFI|;7p=-W;wx18WBrZF(ejO|lJx&|ggbnMp z8+i9YOYI|OWLN2?4t(rlHv5PDu6Ibz;B%4=bay6NF&5^>RwEgem;x6fqk{V9lF}}_ znh@aRTdhB$d?wXOhgeGE=KoPr@eNVwbKP4aFOy-s5x?_d=~-9o|L6O1^q_mJ{Ac+t zH)o<4pI$_BLR1L34EI+)u-KfutIX*a_ z_B)zUKa22^(@_Q9Q@b>|EtSa9mq#fI11=-zat;)IDYjHs7{))aGl_S+5O4QXF^D8T zB~rlF-6#*vhs*TZCA5e!g0G^hFPv{}#g-GW?5Hal*}T$@jMZEviuHeL`#ijQIbSU>WA~0; z79$toVgg)d&>ae*WgE`-Ax&4I+YDy4mgwn5HXe#1i|dk#vYC{SxWea<^HMJ?&?VhH>w5h)WOy_(bLML#?l0N{2qpCFv`i;h zKNp=(=rWqhwW=le4w9L}$B9kPT~R40f_V59S*VM6-6#$?RsZDb|GVG*+qe4fPY^KP z`I}o%hjfO>)jsW!%Ht^{=k%J@L^>&dAX(Xip*%*sTA_!Lj;2*yzox+~-yZrH4P%i0 zJgDhW5w|kJOjj@iTsAP?M(InqO1?CgX}iTB6k$Dj%Nm_i?cDt6h_uyRMf}GR^wX`I zQ(v>`eDVP)N8B>Av)`kyIV2?ccH$`3+P#wgncMv@-nXDDqt---5sP<$R8^sdB$8^X z*pTMei$v%*A+n%3dpf^mJ7R)`yjp!&y0b83!DBbfE-0%4aNmJ$ z%?~aWjf>h=A__hp#v_pt4w-7XjqAWpvi$Z%NSC=7%_SA8S zVY~?O086u!?UR)A{)o*8K?U)`HuA!Piz>%%sMe3Dai;^P?^K^))?|`1BYvMgAGE(h3mOxTcB!%)%2#pM3`P7d z-?FS@E1SFYni_Eb+YkNkPY^JIURt@tB2_IPer+Qp-I8}u8+D!ZGsU7rA$%j`m?{ybFG+iw-5D5AleyH zQiz_VnIYvh-OB#!mM?(&&wlU!{lS<~#c63R(3!Ci9?K3r2)dq|wUwe}aPjP_1#fEJ zWU}n_lnN6he7V&u!JX5aYLiRR8jUw%2o8}m4?*p~j;#Y+KF}R0pw9Y+qHbaHJ-Pel z%%^&LxGsC=dA@04_(tzSv2TlFh~1n6dM)(+%O8@xSJBB)tKZVNR8~idpNkp>lZU`O zEkEc=49k@$$C>O|l{6l^QpIo0vm?Cw3YCD_(QE^^7c|8mwLjcr62fE^?dXpHnV^a^ zE?<%-u;Ax-P?FgEq2dsHo(X`ildx$Q{S|~CYjD*A_Q;>LUk>(rg5GaTUp7VFk)B0pDYB2C8;W>J6!29?xR zUrqgy18vf6du`uDcY}EXA<&gGIV6o@ow~x4N=C~U#wcO+3}+5+k5zYU6@8IZzoXx! zf7AFYAz!z3@=L0g`sN(m$JUB3Rhi1_t)+1jS#jVzuQ2FN)iP-dm^Hn!$3BGg5qZ0l zXt*kOV>>;U?nKu#5#alJk(|M+FPR`th&DC>0;Se?<(1!lwMvrxI5yF8fT|+K|Jnfp z0paga1axujoRssv5Lx{^qg#%H*Kloq1IH|MeVp4p|LK@~9ricDw){_f-IgRwbMPU+HsUV zWf#|8jl#Ul@&DrW{(BSyUE+GF%F4v>fS;KtW7j94!awJc=GpD?Rs3nhAoye33FCV+ z(K2~7-fxn1jq~SHKJsK_gxe}sG*L)rb-%I8`L~}6fdKQ@6$f2yEVwo75X?dZYt}c7 zY>{|1jWyqd`KBAL_YAKx-=1HKO>w>(;WIs3i!(Bs+D*^{q3DS23h3Nn|Drj)P@WJrFclH2DG z9_Em>&SB%JYWi;2mnAnF$d=9-{@YK5f%vC=B|%p$y&E$wBhFe5S9Yf7ZEJQ3ox!k7 z&&0ZoRKEU((X(-iN>pOq)4jGorcJ}lGYdZC_{?^uPf7J~D^X*?qxkCo;{Df^0$o4v z%K6L2<1{SvDb7ylU89j&vHf5DuOu8u4e0t8q|Nf^t1S-0D@Qiv&Y6C~C=}gDuV(ju ztX;KzqZs!h&HC@S5axgFAPu_8DngPt+Z#nb2C&V2JDlT3DuEXFJ!qC1r(5NQ88uG_ zJLv4WpR7j>eo6TL=E{pV7PPT1Bp*8o;qHWdkLLaF_zmWN`-Oi5UAo>qr##jRh8`0# zPqdDJoDW_^3%dA8n+~_I2qEcAG9~bZvFa)*0%gNiYZNKBcFRQX(k|6h`E8*>VCj*T zCjZwC|L)5r1G>Il+~j!WYWCc4L4!kI$#bVWoC_3cWA%6RH<`jEki^Sx;~_t-SdOww zmzM`z+xgKLEm1sT+lXT;DCs78z7qpnSW_QB}+qP;k&-7v;ta#Z3e;I z={HWCB*2viU2VR{E~pUP!QazQG;=pK9tyrWY|AHEYaILxH7v!Dp2Vc4=9L3+!PsKNTuaut_O z#Mt?jJF_JuR_k+9{Z9MbB(AfqU&koym733z&0FR@)o8DYD6l`N2)ZkdRU%|E9qkEk zP8W=1axxCc^dIc&rBe`vD#=XHXwGaYJ&S~A6yYOM*%hQ-2D*YQxOfKlG@?J&$jnTt z2halXegfV3npc-336Rer@_~a;Y7;a0*xp0*MwmaTm;)8LD_l-%p(8vHTjqYI~^hdrweu2^Muc|>anzNqzS z`DgC@zj454&?P+Ebk#WTDK^4j@fpqEGTF#$Q=jC%dDmoX6=$U zB)7$mO23+@Jd$$q>)hVa4YhyNGw!(Q6<&=&9`3M7Yy%S`_M&k_^{Y^yH66UKgEb@K zs2#IFylSBPhTBG0NvWh72|xd&dN*s5-F*Nv`z4>_PP*f(4c69Mz*Ps`Ht%fpY4N4%ddXqYwx}+KbrtG4ql#js*2cvO zttvSweC{R6Cm}d9ky&xo#}1i3n0n($o>z|a75*I>yxgh+fU5zz-)-CooQn4g-$Fr| z*-1a0t?QPL5GcI0YVlv6^XD>u?~3Xzb^gV&350V~3@S1;Ynoih=L zR~vL8hf{4cwRIk%Fz(9)Nj=q$?UUv6`aSuJ^m6cYlI4Pz>r44Vr!h5?wEfv5wS*Ds z_0nwE5ZA8E)8UNNb5GF#R|j;hc~%Xj%yjiTwGR`-^(R(IPb+t!Yezp^htimcV_8IV zB|_@vh=mt+)M~e>E^sJ};ry~daUL42%hbu?Wv&6A54xZWvyvIY$7Z*jjv!R~^y3(h z@0;DkfW&fh2Jr^emR8ho0R!qNPwozqOSDOiHvfiKNO`Lq8}iNPFT5=LdM^dGK)iaO z+kjwinDfh+izuGg7uprYSbs%A?37zxd8P!NZ-J~IPHFEk_14QK8gr?Z>Y~9InG@DD z)U%tGuF5THeACIZ9&q(RS2RbM{5{nG{e=Gt>jBG;9H-*>%#&XbjX~k9KYK0mp1&Ej zK)DDPzt%+k-ZjTK5DJ$_W)r_g!l^pchWX7$7_3h<0NsODPtlbHUM3UVVc&J%-89>zEe zZrG5)DMzWLOZ01M^Kqc)w<`=|U0-KEnQ83%t_I8}%j!!ZrET6eIR`ixR51urx=3QR zQ!d}et4&Nc@pe(bH3Hq2`ICFKEB)cu9AsA<&h!-|e5VN`{SwMT$eGJ8vB?L!pN|M> z;(gc=`c5=--7s?23r^XmFTB=gFALuxPI!RN9b?d)2(o%Jeez^?905C^i*j;h1$W+R zJT`WRbo%Oq*~VW2=JI?8$9K`Wps=ky2?CIDPB(9QUH-VLd$K_WX4P;@7c-*6XRO(RX6 zI%(_e9ee%b+ttHP)}CE!miHTW$>anE17^7v$I>GkX3<^Tp268e?<>GH2VI)c&7mRY zjD@b~K&!8VcIc04FAwiZ+KuC}lM_%F*3nag1+pV?N^llAm=yWjHA4_x%fkJhsgb20 zd3o0NZa)I91?bL8pjiinJyUh$)AF`w)Hv!eA-Ug>pFY-0g|ToX67Z|gDw=a+!7@iy zFnzp-;T`fOUFEWQP4mbE&*&MEfdmJ*mY`egsZtKVYfdDJ?a(}&_NOy4^~|a6R?e;o z{ewI-tYK?{JQ0(XY+fAESI$C%zFh`J<8q-@F+8YZ8%1eH+j6k~U5CgjTE=XZU(m4T z^R**b7jF%^H*jS7D+|7F#B)15_&0en3Q^gzISzYy%`gT`V5vj%N}=}GqOEUzC^Kk9 zUZ3of_Z}bjt`GbSwrhjKq%HF>|!J8{-!*kf^!8QtTjy z-MTt_(DDg-Ob<8P?aNbh?$oMRy zn}=x-#r7`#Rb8WRRk1TKBBGy(GWN3W2Mq6$smZl(6Tb=eynF`ye;BSTtf1aUOdy8U zlh6UK9q39#X#J5Q^v^1W$}49JpmW~e%yl!wxE5JbU^VvqwDluR+Yg=Fo`^6^dxQrMPTTl3oY z#OnyUY)SSD_BUO}%qNJD8@BKBBpwrwmEtv7`R8lS5Rzjq;v7#hv@q-y=Y#leveRy@ zNYJF8vprgPCI^I|?+BaM0oMt1GcTDv+0;5c0_7?COK(4jC zd)7gjpKgb2@U(~_9Gt&!1>JfLODgLgXRhy1WM-D$PVR2iWXLdk3uq3RE3ylVmflT4 zBGc8TCfVg{_f|pn3X&~sm$lfg$_YZZM$8U2L*RAx6?9=~A~G4uPNSP%E)}j}m}YMn zWj%^sdeiO-hoEG-3dXJ94ia72nMNB}JEiJB`@cDLHBqiClQ@z8j7fCM`=AG$H#g8F zN}A1pgI7TMkY zsYl;oc2Z3o!lM_=r@Djg^jl+i;#4W~l#L~KGhSg7`?{y&?0}w6vO0o@)lzlbi#8h^ zDVbEn437A10(e-@dx`xORmTUR)+)i_4 z-RO-Ynine}z8mHEKSt8fAi-cEJ4xxPO2C z|NZyhxX=@DVT#wWo;wHcw2jJM@rMqREIwwcAx_|r%+Q|qKd{2ms?Cm1Kz_EvdLBkU z-%!wXx#v%aH&kk9HgZ+fg5i~j2J1+@Ko@4{ExIQwoLIr$p1LYF8KzzrsdlayG6CvB-C+oPQ+2<4TPuC;>i7{?eU_OF~1E2CA4SV z6h^Q==>xj64|;1qHZu{Iez+rO=Dix#oMV}X+dl2i*BlZ{YSOxHli5bGBttH-SVuM6 z;_RaMk==9~MM@caMM*FzQ`=tj_w4-FzP_M)Y&X*Dd7!f-zN63jQ_?zxm+i6pHAhbt zYMV;ckaHf=^|Idn-r#urN*^ql8B*$Vwo)BV2X~0%>r1l%w)2L6^OOJPx%@!a=viW} z%xV#Lvc1OUy|D_T2vjd>?mas7ySG$>-<$fnbZ0ISGD!q9nc%Eg^1PB*5f#No#sY$j zCJ>aAnV7%V0`dBTZhInPqHM)M_FOM!TsVBzNj@9Vq)sSt)2HK*bEHHcXJ`ASI^$TO zIMykK`{o<3g0?cMU)0r=*-jshhv@xZgY(A$psV847aY*mKmQc%Gjcg>V-g;z-mg=a zbtIZef`0v7=aFhgsS>WqlIAjllIq}y2*R9pyrt-!WI;Z)-`4H>S704TAn0;tLBsbM z@P8Vf|MI5IiMZz#V~@BBYz~ocRF12=^a^$viy*x#rGegHCVUop87`@4i5aa9@~+Kv z@w6phWDl4>3j*CF`|c*~aPN1vGH>&oeEdVPDH>B11*%CmOO6xGCImkd`09EvZZOa$ z&gm+AvUXUYI+CHEi{k4y{)#*P+i>|7Xy0Jab*a$g{Dkj9uy1q5X;%LwF{eZ|qcL*J z#N=~%Tq#GDzem#|jzl|KQTTM}8=dK`1JwO9c>_uZHe$1*ZaPlAF2D@|-JKn>s+dRR zXr;~;#za)eQF}Fi-q#dm__~ZT$uuT%jZkH_?>)$*v)LTxVnZ>7mtTE`J-tV7Av{U3 zmp)1K0rQ@rpevcKkrIvgiTcy+t)+6~U7clmLcZ{sgjjxFT2iUP$+c6KA5;s049^51Nnb_@zMY{9CWA9>tGf2 zKHfW)Eb+RzdAOgVqKPpuNW-%5eF|S%x6R^G;|uwPj;8bOL~tT6TwFj=8b;&u%lR#m z+i~m#it>=-+CTE!jow)D%#c~=GRSRqrLtQJr{|4j^qqlO> z6Fx`i@=r{ZT#9uU;k*$o=n~0~B9&l2DiU;~!rbhB3958g>AKV23sX6ytQaRBmyXkj zdIuO!*T8k}MdD@PTnoG0b z1($IT=6n6CwzebGAAfhkMZu20_5tFJ0o^i87789S=%IVetq|i-!CPD0lJ3J;)M2R$ z^6x!;fo8OosIzyINy_nzcQE%iY?Xl2Dm=t57tZn4!5Qbt@n+enLhX_z||ZNB!hgQ1Gb& zXD(RJ6$iR5^{jV0rinpy=(hd(K^<18D%y78yeT<`$|r2PRR#Q)(d~tDTu8x)+<_#R zk#;rihG%N~T#D}BO^y$(bv6E3`}f~{5f8eD8uIa^PeJLQa~f-CgcRLqwBI>E({>jI zRVG}u^RIr>FQ|w*r!~oHDg0fyg}km!n-NrY zOSrXmRB4pzx3~m@8}{4{-;|xK3O~TxLpNlUVUxdq;l&hzR;L?)RU_F0r^LO1{3u zDe@%Vt)iI{5Tbj5GWm*I4r8thxT&B!Od?XTiJ!_}aH-Znl|J>>)0IEF>;oU7TV!?H z@-NB^D5zc(_@bDW1!uX)2cENtmT=30ZnBZwJwB}q1W7Soz)b_)dWLTLF^g+;*fAML zGlZzC)yRD9cVXr)9J|dbq93eEDp%t_>JBgdfbWw^l$a3p6kBPWG(t2n_p*%k&nBAA z2HfwU+uvU&sKq>LAJkj?y}&QswT%rfKt8s>&ZVUR8=5j%V37;CZ~JrIos{wib&d`* zCb<*b)-Pk@7;NY-g78OFS%8}ky3Og$PxTN9;ymAoQRxI3j36N^*|GI>)Tw*|tEK#D zO7*g*rKX(j*Eh%Z)9D2ap3}DJ_fM5uka}19SM<9k-T`g~=<*)2cLYgTWCV0jTiY@D zA9`&0&M`pHKIE95xx7%xe1PFsw2!#0W=mK9vcK<5CJeU%gZ#-^dpO~vDJ6kK92Vea zg6;|h;&nNGZoU8Y^mjAg;DUJ+xXoa@XkU2=S2lu^CNF*uX&937;AZ$b-h~A;moy=1 zOmTS}1boW$4_ecat%ZP_1-jlc1ysH%b@`XWgu@%WsW+(6Q^`B0MCteaPFL`jXyNqV zdwL8Q&I-B-=g}TlQ{Y=7e!NEQj@TCuxH`(hz6RI7WrHresnsjZ#&9y~BVyPgp?#(! zA}Z($sDZ8KzZ&O^zwa59`|UQnEI_ zZR*5Vh*{@>o4U|G3OgsD(bK#$u(KL604^G;4!K zJg9XS@Hy8vdNE@vWP*ge%*}Gta5bZhJa;IwjiNgAJ*f$=*(d@}jk0@?+WO$ZsY|mt)~zK5xLgV0mC6SXOnmg4s)RAGikHXxmKO&wKb3Yy zyS-VnkENR53<2B%&_x`>2%nH|$8N3gYZ0qlWAauS3BP>L=%a)2%F(D%krH{3!#{B( z#>ZM2mSaI!!;`l~8=-uWX}_(;!Z_gIbt~W&f^O{9mtHwAa|;Ff~!(Ro0kg>97( zw2fHu;90nZrstqUi&GBVx@oD|L+OqL$!)*#_q(!biI_3+XeZ7Oms&00MuXTh;9r9mV(3dKhaoBpDg zvgCBL1g%f42V`2>t(|yHGFQCT%FF4wK#RD~Dizry6v(N)TENbPH+nPLpS| z$8FLJf9$>0t#of|*{EX_mx`?CxZ)i~vwQOzJLaPQ@{BalH_@i|?wj;F2X3D{mWLBK z9;yM|AN>n%)n}75>OXGv>FNj6s^-p6FH~!?BcO|IM%M8mGs#vLgex$4AK#9Ci)tCh zUV!e_6?yqCL@uTAg;&4`tnaG@U3RlW2G~n!3(jIO@}LW3lUU)RsR;|6l;r2kgdDoP z;#dqdnCn6l7xqT`qC?cMvp4fqRTjuj>$>oz%st22*T8wJ16|>Maxx=Vb?pN+8BMMf zqsGERA(Cylo5JhV{NVak+%r#x88sdBz0q`5X5op&5Nsry7CpNcFX8p?JM-yrKIwp4 z54u&Vl3Q&)!Bf8?aNKPTX3Ud=)OwN_7<@RqmekTmym;q@RoZZ)9_@p=lR6-HG)n$h z8*-X5%Y+ZSXma|I3v>Z)1L*pR;>M|}!@sVI+thW~w-Wsp440mH%4!JHC1psuQbFt= zsP;*svOTmGs`>rZ4eNc0cqx%+;jWD(!(-SwQ)?>VHiE863ft)-t5V$cu^#?_14kWh zv(f3cWq1xJELSPj6wiz1LKBVw**7#6kzX6=ofk{zx`BJ0oWEhw@+sT>O|r=Ww+VEG zDDo5Gr0Vl&uT7I-ySoE8@CoMza2)1pKkGXRc6F0c%!sqmZDHC^bh)#lk|autej}X= zM$62pg7?L|pfm&DZ_S|l#~=SA0YnHRVLQ_eD<0Pm)`WEZ4&v7ypW~e)2(|r3+=Tn& z9NnTa1LTPfr8ksIR|lS`n<~mehHPIPfBr=I2E^L}y36mG*}EEfV17k^X2h;!cqD|- zsy!O5m;y52D;|x&6--eIj5nruGJe|sAom>^JuwV!FBiZc`IEVqwsGt`VC14 z_rFX~!|v%T`i9c-vv{b5Bx$NQ7FJdF)`RoB?V#Ij2{Svf;r;bYGnbT~jl_FRfM*Pn}J9L0<(f(cw zN0XFx#-@Z?Z(Q2S;Yrr{adKOKoPS^L-c|U8De{T>4er8D_8nC!0r~^}{y&d+y&u3adJ$Z=9ZNZUMf30lWvIQo9~!^P?% zN7Ai@KJ9hu*efS^IPpZE)?(ZZBfS)=i(5-eFBsdJa z3LPv~i>oi;)EG@4lG$xtL^XZ-5_UU?XCiAW+Z9Cjy>3u-^!1~h8q)HQ{*~#bYPZ4OIYIN+_3Uv~>Gk9J3(Jxy+FhW`(YwowW zdt4I_c%AiuZj;Z4pCyWh#%^+$d6&VWp7}*2MCoo)ZLEq%xpFJu>jRMa=Nl^ zd4`V%_(cpT<)}oTGE7MAV@oMx8|_rfLSgO#&3oFI)Vk=1e!2thFVOwH&H8+CGE{`_ z{)@!)v)@TNtI7)r^_LwRj`dZ?PY=@Ai^x+Yl&T@9?cVjV%*l|u&t*yn_i)Ou$GRk$ z3e9B!w;yzy8tS4(zaF*3m1^IU#BH;Kp&SxTUS-w{xPzdp<hXx;VeCU*{E-m z1Kc6db=6E|4)2t}&hIp1xYr0zkUB&$@>~(5OMDkh4b|@-!E@$MqLy*0P3TYR-a$Op zx;j9G3pLlf;m0RF_TF9h3~+}*mkM%z9vb`L%L2*meJ_2q9QOOG^;@(TqgqcwUopsF zi6T3!smU-2kK7;CBK3j=B8t#__@wNl0Rz(8zbGn@tO0ifbm!dr(eq4;nHzl9q3*K` z3a+fJrk`fTeBW*;nQRCQ-iIpL{F&bh+l`WVhpb`MLEDmKu+W3HDGT}goill{tlQ^>RIoyvNgUeqxvf>=CDkp^~j?%4uA< zXBv6GTIu?v+=W&jLXCU^Lt2=%?!+2U)dY{ zo=$KSVKFy=vin+5EKVUO_3L@COygEz<(8FJS#iqEplwY0gXgYgGVZW>Ab1~7f$p>w zpY3nmk6BC1Nu@^TpQ3hVm}jE!D1tOFHwZX(+COQEHi}80vn1>z$aj`16%K80Vv@s%pCvB z{CDc#22~U^*5!r=zHt&w8;n(SFB|);@U?>Pw;9lN8ZPnYo1J3jO>ovy$tq@8w_?M3 z83{+U94~3-d3saeMUSm1jhng}%5xEpLjZPUG{)nvCUvu4K*)lb)hxt&8IvalJVE zjo%hVZ@Q_Gp$52fpzGkH_)V(QsS(?xUU1sH4jQ5ctFtjj{8O%S$(d_+?-Cvkf1)OK zNNoHpzS{7Sl)2-gRs?eNb!9M$m#lCIvtdHXZ#tVXnl|qwjLjhC)H!(|-UZN|i>6t9 z418$Gg_`qFkGYJOfiOk8jI)l<+ML|``a*jn>@rHb`R`=OnQ8A3 zNy25?g^b2mz+D7gE~oICgM`CkrB$I)t(o2^VmM4h(;oNxiVkYTq5Fd7)o!f1nP$>{ zRRjJpHJ6#gqZUXvRES&N-b@rK6PJ*S5!5E!C<5*(=n||nV;AICEtLuu!QgJXe-C$Zzf3@%$_f^F z*U#J-kpHUX(xfXGA$*8u0Z$2`$Pmt>71|(%Q+4i7T1TW_-ZbE@fi9au8#)Z#(NM3w z)fJr{3O4ua+W~5?wLh2B19HNWNl0W$$y%_@e~d*+j`Eel^mg1GhH<|bpq4Ug}#CRH0G#NJl;9;{^h(AY(49mb5N5S~g?_O3FE z=;h8)qWx5nUe}U_9UGamm>kXo;@tq$R)aQHCBjENf1!rG^L^V&`>lzX_>MZ z@d=1`3v^Rgo@IqJWz=|X&DN@3Y13kD@BaBTfgIqP_+1~qomX%1-iqg3hLzl!LsDL8 zjjQm8PNQDi9X@YPZo?7rn+!O<*altQmh_##&*`}(k4IY(SY=eA^pF?H!2%>BG6@QQ zjM&GDge0cFQ4nf*vHLeCyU+NMh`v~~_`l_-A@973F|V2WU%daW&)NaqW9a^SiyvC> zrJw(#1~x%*oMs(gv^^hBzFWU8z~dgD)F zGN)!t&bMHIwr#NK!-gZQJ`F$FK!B6V@_#PO-{T(Wn%nOFnz%ho5w~V_PQ7`v>nBcR zos+0>Manm=T4NkjFsG=#Vuqv8&U;l~eY%SKD}#4%7P(4!eNa_oN$5-Yzxf@g|E;Ur z2i@Wgva+#Z%WE+5(%Y#wJMF`z+{^uQ@fnvB?s)2f2rQR<)Pps-qO}? z7S8%8Wpy4^R%2zQ<2wno!vW~lWC>7b_fo!gg`BkRj&u+&sUu|CUR92&vT?}AZb~Qo zxjo|plgUofxUqMw(7bHnF=>8>!tcw;;M`_QJY*B~Klk7Dg@>T~`V11889T9JbemSC z#_AdyVoRDoWAOdNhj1E&u$cm}b)Tz0!P8qqH8Dzx$2waD>FV#}E=|np)$>BA^qP(h z|L6X@e)9-)3HR)D#8HUYs1Q?wJLoH7%DeIWM=t83_i)6%(Y*&+t zS+nys>2Q&dd=^3O2(i{N;+Io#Rwsd;X=m(NyWKh0_hC5Ej)4?8{>Iutm(LXpmPSi9 zUKMb7nXy@EUjOHM|2>|9t{va+i8#M2rhVyjt?osS?KFl@qVLYJbtG?P?pXtS%Zziv zp^@xqvbMO%es;PMR(x{gehg!hnqkt9YaV*n1NN)WKsRdovJQgyYb&)pqOB;w^bkHD zA<8tto6g`(axH|kw1V_u-9qRhJI>(&eT;!A@{Xl`Dzsouqk)D^RYOOdDe%2{4!Uw- zOhUL-dKj#da-R2W1!hBy++0XdNNM9y``<&!zAztY;yQWLVHC{l;HWe$UuOiM@7uaO z(A=?%4LGAcE++i19saEoy8zvWp*C#t5N6q^QS|LUe-`n?;$p>A^$C=qw+hhJkvv!1 z;a(y4oyFwKyH#5}kdn5IG757n4=BDd4Ix@qbVUREJC~q~*=K;||6ZPwv~X+w8*~08 zy;q;PnIz<8$as!;OU8Ollh%uwEMX`%WJuoe1XtU#j`vEA;o*-`Vgxr9&ls&@Al@s` z?e6~Ob5%S0z-`OAOA#1% z3l!belB8$;i4Q5Cx|QniY0(DFxLplNT&H>_JvbaMOT6B{IjySMbp5qkq5o<(C*9y8CLZ^W$3cGaGZ_r=N{ zc%K+ZJ<6M8sM^4O^)2WU1wF}%{k#-k(cBYLW= z+}!8xk{Bhh##<41sCTW7>xjkJC85;+VBO?H-*qDHa&EiNK)o2ihLq)w7m0GssOBGzCq=-z`aV`9XT z$7`!Ar15WdZ)od2%oG&uy%YJ`lL5tamtqOS^dqfv7qg}=4w=l*Bemk>sXsum^QJxp zg2IF$g`j8@9Jf4xZlkQel*0+vI{iooG3+;tov<|N{6&UGRSPBU*&mzdFJ{t94t2Kv z3-F8C^j=Q!AEgUVnB%1vY-e9pCSIo%*#hnG2)dORU%8cBBoM}WxnSQLf4xJ~%MA*4 zl!|pQwHiOGIHze(uirH3yjs;v$`(hwtO-Kc{p?1?{DW@qW0SEiWC9`JK7sBC3PN$C z>Y2(n3lyiemvmzhzZjN0@31lcuM?0SzprCY?r=_)1ZH1vEQSp2X~oZFVCxH7;3?q} zjd-9iV9A4Zy3e5dA~N)o@b|>*hD5TK@Xm4b?Cs?{@@`)fN`_tCR2&0_{lFU(WJ@NG`1yzcG9HSn(PM{qip#J{ze}6DD z)~})4K0~BV;J3`;k03AmpADW_&aD{N zyLcBm5c9+^syVz)5@7q|P5e(6g}B-iN#djcktm}UQt=a9GDjAksoQHc1kF9!@%>IK zz_HyDDS<}bd)QycE>vHCk$q%-**V~uv~x(3%X`r7dr`xF;^y@7D>0eno`rJ z0w+1H`7Z<(eD13x8>xuIZb7Ry9NzDCo=wWrvfry?7kClRAp1;}hy{Iv+y~#AaGP`k`+^u(U_SC9uA~Y&t6xUYX+PL@ zkAWWVsZk^jLIkX=c3F9_6vh+9>@yaE zU{AzkjUN~yZ-knSWCC4H_H1qYXZ^TXJpNaz{oi$l0J>PASyBHVX@3q5? z^s&ZPt~3|OFCyq7WGVTTL9IY2a+dW9EfOwHXmt*8qprQXJ zl~E7^?*XA5KX(~jG(}hHd*0bo)%S_9l1=KCclw;(*Ab6jj912- z%{hJ`g#s=L=#p^-N}}bMC`fZ4kkmQoMr-_qh|K?Gspvyiq7OrP{fk$RMBIYM!mpd6SZ#3&# z7ky6)$=ZZiohbEV`&osp2OHkxU{qlGPL`$lfy*g9s1r@5&W$@W?tk;&|G8+Oo2_!9 z%11jdIig3iE|Ewwo7dS4?-7zGi7L3VgfZB~yk`PGinUGbEI-}M343oyQc&<#(o8lq zDiHP$u}kOn5y%5N=$7FQVv)T^FdukFf0G8KwEU8)o=%0pwSonIAdRB?a!c9v*-=4S zkkzdRCaIX`H>Ym2SFU&yT9#nKQqWHM$|&GsfbNMXd@AJtRdzB)sLXy#HR;qaMGl;u z>qI0fht{7mvBU_AQhTK^ylL)uwZ@D;&cb@%RJ!|%-eJClvPaP#%H;ztCg^@YF;r4k zlr!}ns%Dn*&-_x17SH&sGOL3^*g06owh29)0Bu_R-GA_+f?Xy{TZZY-FFp+^ITC@e zJXItev~>tk91N96!G_At8)ly~xxXa-8i~_r z?VF^PRDo0OW~pD)A%I0G`A#;+VDZ(;Pa9_oD~)7ImZaUet=z+TXo~&+&pK9NTlN zl}l_s0WL1+8fjjg-dzeckNj%dC?C-}S+G-qwT~=^yTSTSA<2Qb_T3QOb@p7k5Ia!0 ze_Xve%@@DEdyo9N##^W?N)j0b+}FbcUFUcFNAIFY5WXR2)NHdRQ2;~j$~$0%2u zELA1+M$Mt$`TC`Pb#tr({X*pZ=}|IQMV8?o?nG{`)EXdOQqY}x-oE~!z$wgs>@i^1*S_! zi`w9@@AnP+9!(2G!i8s3x6x3Z-!2F8oK;hbw=v%q;JyRhNbKx7;l2>+5%)()-8O|W8XHqX zAlOJ7_Gl~HVl@+jd7uPc(}aXHHW-|Pd`t}41T%8FiCX(d>rQ0N>x9{*({tkK z%S!^&*Yd70*dW$$h<;VE^D|A|x;WI5+Rc`~b9eW(ikEcte1s?A9oIEBVE-94=&otk z?uO0FhtD7W6}L_rv1I!pgTGYurE$9H2aPTiOk8uir9`t38G;i`ieY_VI!EKre)NBM zKm8>TNALX-*DZl~X+YO=!h`eM48;?SFe9er?XP=>5pUOhdII&e8-CCH6NP@OY)-afj@tfT-R%G7leD0lZE~w9Z5rLGCzg6rICOAJ zz)0*$S(R75TeMYU_opz*3TC_<%^9Zgp;n;^pI1DnJ1>%X(KQ;1w~RvIU}bq7aOpr- zpu}#Xe3Q_ZWC$Tb3eth`g6-ZkLu0xmu1&Z`W=8?&tD#?GPNdQknIy3+YH(4x0O-2h$IjDJ+J%J?q1 zn%8ghUVgLux&Vb{Uz%*TK1+UmcuwEG`M!&S25{elE-thOJN_BX=K5);4otU%K2`!+ z)t@*BMmVi_xI0!H1u=N#zwf4x>H90Q9fPKXbplePY zc(U*^m)A8#BD;}WM(^+?^*3p)QfHc^ZmvePzEjWXyUkyV%#8s&7KraoD<@^6jeD=t z7n(iPr;6CV@v;N)GJ-DuK^vbB^Jh|m68Zjq+^3rvkxW>Fwm;IARN9{vGiwN`rdV{n z-QO9OFnSOilfzZ$7GB*)Ah-rxlouB+4$e;jE)(d+evCA@H#_Fda1M7~3vkb`v}%We za(K#&WMDR{Kf=sy44Tj34s0#?t5)G--(B{SN0hC2>mFNGqodF=WSXT4xXhsIBT$L_ zQy0CuMyITd+o=wR_-A}7eVAeE49uDE!NUG334GFN%J({KQ^-x$c}QHVVE1)1y+|II zc7J%qcVUI#{DB2@x8`Ao>6UOWGMvI<>^SrT!cDqp`1+tf+iK#3&Eu-#O)irbsC3yI zhpGGP_J@TwYu3h=(c$T$aiwn0*Ag3o@v?$0k7<>#w+p`7&kDH3&Vv^Iy=bEF_ctES zJPe4>)c&=-L|e~xfn#Pt@et}i*!4He49H|q@kh%p+$BgMDHKk$fjqE*?#vJgQOTn3 zEp1GYp)X10J>>-)H#157h@S61<>&9IMvJ4iEAw{s+09P4pQVm@6Yd*3x{Oi6Ctnzl zj_Rx$(g2qobo;-`K?Mt)blvE$$y|T>+F(YGfJ7u%Qa+;U4=uylD_S@3X^+xhfYF83 zFA>EA-HG04kJMT7CBy=?F$7JR6C5WwKv$43c^jpN{=XeeIBhf7QH=rV`CQDoeeczb z8N)TP?utqRu@>ynoQSm?K1g>qm%gSqHQogB2~H4Cye2%==000 z_9d68m+Ze3Ht|JcTm{>un4ve=DY}o8%0>b4a)YjHEZ$gh%fHr5u893J6osUqXsF^g z6V@|Pttr=rFfu$t1hk~mbTq}@8{%sF?~CXgGS7bcOv--}rdcLiL%YH6Hy+T<CH1OTByiZU0f0nZ&@>3pRnl1-Xd! zWDb`Wax9_*BS}od^&p1`7mqgPBcpirzbfrGAoIQ9m zaLWEYf`j?({sci)*z*;7ZZz3}Aoiu#HUBG=uFM~dn|^i-Z{ws8t&apo>fF)ywnUFf zm#9IDmten<0Om}8p-)?lNr+R$`g*yszq*D3!F_4ovRsqZDI?W6`A-VePmL6CRF*Qe z)MQjZenmky&f9vK$I@uQtbEl9P2l+Jt!o9T332DeBjS5T<;HK{s`N)`9pnw=4Kxhp zb}I_m7M|0K3RzHNo{W~4c_qzI09Ooj|NYCtBi0@G{;;;8UDnwn8EDswUjfh7VhWv` z&V}&9k@T>xOm8u0gsqBL;qP`ZflFPkmRxE>qR24Gv!^8S|MutqH=cb2T~yE1AaOx| zyYB)#3g^>QFibCysA3qy>tP!-8*q?=4i#!H5*wv(T>ofG;G-_pKGwr`s5p5<7RtR2*OGtLS$VTyv_a74!-BOA6b)L0g*T95+bv&pgk3}g@ ztu{u2$hXW%gZx$xA{^q(6sApzrhLHt1iDUMrtoPLjii)~XH5c+l$T-1WHceQuTDHI zY7WJH!PI%`8weV4PYEFjsk?e30?gh#F7Bo{ zzdaSx9-`Q?Q~tG$TA&U+YHWdhVv?ZyuE~B&@y@qwT|BT@!~m|HVLail(p~>2RxKgi zUsQb+BXfma{w;|p@QMPN%S7%_lQ?r9n|$~t*iDR@>rGG3fOw@q_s3D_{(?SImCC1Y zj%7-0R|)0~Q34E?!zHFhiKP%X=`^~vQUcmJ8+tVrLUQWAwxP=Ax)#>VTLmo`htOMc zztHM-)7M8^L**%I&+nOK(*Vi%f6XoAEIKfLn|H z{u2kf8%N-h$^G!;-=vlV*lZG}LJ8f7QG&A`TZoGPt`lbj@*oSkYF^Y3g(w&J)41Mb zUYXw4=vGylBc@r~x-K8ijYH7q z8X!sbmf6kWVLCvi4v7fKgrB`E<=@zybSk z!HR(WLtSBMU+sB&rXw3z_tXI0=r_I=lJkgzFty?smej?>T8~4nn#;YJyl+L{V(lyA z$Dll2M2X$tag%Rm8eT>GbCrl6DnB3kP3SoDlkCfZ=d-?mt^n90u!0j7i!My7#Ihtf3#UMDc?{K4Pj!vz|XNJ z=w4jzUhDB;WaP`_zJBDu7Q2)F#{i|wgLd$kxum9h(`hV*oEzte(p;`gcWS#|5w34~=T0jmBQ?b9tc&)~BBN^7{ z&f^>ti2?}~r;N+2j}jK~SF?}a7Ups0b4BHRV`8upu?ZXCYJ={=yT{K)gL4jF`wv+8 zNobrDe*VkUWIc$V7O1X18t?6QB8*6CQRXXWM{z|{rafm64h>w_o%U>_($7#Snf?t?L`&z^9?SS)W7vMMa% zw7q8XL-lgfH~BYt<`>x#&JAKp(+d2W=pBYnRLBL=fU5_(Z*L#c)D!5)X?mH?T_7Ok z5^gzZ{1@!ADPl%Z+7gPJ{NlHgZp)S1tP_U#_Eywse_^6Dep!iwV!$l;tn@(#od4>B zu4MQGq*|w{=y!A;rMG8E9vVWTDIhI}AC@+p?slBIR z3m+4aPq*2Z|K*emxB~Hh1>F<&4;k_8FEXfX?xvp;u-v&?wDvs?2|)lL*P5*UaL@7oPq3?x5zpKy^m)7hS1 zwL795wo;oV|7`P6N?uw%5mN8ONX zhC4w=w|q|(kM-)Pist)r#iYsgN7@M%g8up~eRzbaFl038yP>Xhd8jD(oSA^G-snrJ z+|$TP+--xnHKCbB3=6gUo8q8Q&?YC%2u#WMgedxZI$IXTjsiE)0rqBTl*-3W{R@mR zcIT(*l!5boAYN0@)geV1$ja?i=w28!VUv1iq)h2kkX|1W9}pRy*O9_LvoB78wBWUY zX_L%zEWda2ooczb=9M<@5MOMq*e@0o+byW_#U|Jtm zfb)3LGgt?=0A0nU*1sH5H~+fl*w~HkmKVwu7HpZ>m9@$ZczxF=wxb(SmYatY>Sw&` z2rksE^)K^Qu!fSG!h<)W{db6JG{8EdCFlm+I8$pW4t4+7otNLH+7THQL>+sAo4FYp z?akWG+&XI5O8)Egcq+l4@};j`#k^gYNyfi%^wGU4kwTG^c6AfTuNCMTuFhhzm}yd% zN*+Zku1>GY5U9xbng5jy>~9HN+RErFG%#v)R6BrYAHXK*6y z(yY(|xYnS%>L%o+tvE^ZNr}#QhwvxG4`o=cz@ee#QYeZ?3eynB2ZKbywbX&3t~`N(lV+g&@lh1A(1 zQ<59~$XQDH*}30!0qNhJh^gT%ALEb@`F|r+5A;_#1v49;Pk?I+y67i6{1}enu^N*yf!zTimkZmFo z)>h`hdCRUU zz7+A+=2=*FJ!;c0kJ=1Xe5>f-t}H}3(msjLb!)}Z5l!QMc(Qp`(8W7(yVlFJo^T^x#X*`c*+MRmsX*xS2=4zcDKPX z(Z3KjEt@F%k?y`4TGCG2HXIR>3c1tw=-#Ll@)z3UZ z*RMo!+iI(;ZP+M_(W3=cAsliLs+eXG78yzyfj;$BF+9^UlV`k`KPTT1rhw{eD(sj1 z&hHVG2AOOyZ$vKQ;y@m}Kv%#fEq@Az3wy%XA2XQjAhyh}UX;SXD&|K}dz6Buyw@r{ zPTTE!&N5{|$`?YhZ1wfLqXF%7=DlB2c=bo6`T~IK4Z0(UhTD$SCM~xbp*;Sus`Ny- z;#w7v?%pJo+MLAXEe}&@&a^y*33Q%!KgT6uND|MFER5F@bjKv}Aez=)?k52EJLvur zx?mb@kjiX}vvWi-5_}?1#WGAyl1Wt!{K;Kv=Ho4^9s|Qp9beRVlh}|wek}IEX9{Nh zN%Y}dveB7G8P*eUeL$DYER%gTu;FpZ>N$hx5O&ksXv`@0J!&Ibz^Ti8SK4$E-(z)5 zcbxRxcS2<2>vx~NRf(svV<#(P&cl)EIeZ5D%zZ&O&<92UX3)xMLe zLq9d&s#iW$#t3Gh1MTWwQHYj;bzzos2%M(|fbNcw&Zq?M*M0XDy060c9I_|RoPyZp zn7>{Jgo)3-Kh7-OQJAFWPF@Q~PC>upW)mtKP@Qu6-7i;iHMZ~@c^N#99tgU$a&XIx zq@-K#L+XC;;t}~hH%F&N^DRP4G9(>o^!X{m)6+`GNTOf1`$cC8ueh0P?Z|(TMuj0c z)5eNh4fX=-azUVb*8fKHmioBG;=N&>=Hh~rtkHtWw507Al|I6?mW>b>d+Bi9v0bsJ zHm+kr{A_3*xrzDJl)Jo|MFc;A9SwV4x)^YC@0 zjse4;F*vW~Sxt%JpHz#Ic7G%8OAyqL*F%oILUv#=(VnR5#DH>vZlv&t7b`7ho?W$?j0s=3nBtsV z`bXTDwuvdaqiny*9;z_{0mFtjJvjb`fvyqBggejUg6YGZvVvC?!(+jmuHheudF56C zE(u)b2=l6|jP7zo`xlN;%pd&DhYZ(nSGnCY>b{#x+)_A~FJS#49CQ^p741|#;34qX zT|d-L!b}91i4*qB&d8qDDj1(5seZ^vAA7o1_mh^=eXg)%wLDPoNKH?OWUV5JnwIYRcGSDaoVD(4n{8YuMSx$v77yJ!FAT6JAU49I#R62C6V(0d58yHRLt79n&{OewibH=&7O=rf$lTDiA0ezWJIW|^Hz90 ztFAQBy*%6wdQCC{3BLC(bmPL!SNZM{5+LYO5Hc*><(61QqHpnd==H(34-1c|7%>lOJiGPDe05=hI z^&pg1V)16_$)@OXpNgqsHo9dkO`H7*lAt0d5lL*3<8E*3>|5r=N-wg&v`q7vXJ~KW-@NI#+*M(jS!{_VN@( zuW$>nOT}Bpd{3@SiONDE)Jfmyy@#~V^QZl`4RDh|m+Ve*v32lSl+aNQ;_8%+ep!R; zSG$=-J`?J-B%J6}v!H_Cj|7e;4zb)Q(HDjwUEMQ(3nN~tIfSuy+&H<4{D7MRy8atO zF&TvCtJGR2M%@z6_%kL7eVd-s6Y75?#J5y+Y+poYs#{6lWi!UlnG5)eqA2*hr773w zU(AF*b{AcQUI1=3yN)x%QIA?6elC9CAex-mbACV^`d|Z<)O60#!%x+Y1nHI_UOSm9A3D z31a58Hi~fJdnC<&i_!~CvD|2t9OWJg zqlYeo4=dj_b2Al^*Sw*`iHWgIT|Z z&4obowbMTNS(-VUUkb6(BOom`QzK_maXh!1d7UZ=x=;OK0u_%caQX6229a!K)^5g11g3!d6LiUYwuzI&w^6Q@ z9bomgj5TTM+hqsoJd>0}$_Pmim+y_Aa2_rY^%r}OQeUEo`Ej09WFd6o5A!UU5C*yl ztGfX=2Xs{~v|q1%yuN6fX zB!6{U-Tvq(np1sy7f+gyDcht_f75c2rzNFx{=_AV^bV35h&K;($x{pw^qMLu^lmr4 zDZR&Kh^fzX>F7)69*BZCX7FWokq{~L^>DlyHX$Ks7Nm2G5_+in^13&_bV;_E+@BEy z&a3l5_tTXA`LT{kWms~R38nJk%uegf3uMd7;kNQ@!7r&Cr@h1P^PZnpue=WIJ$v{4 z&YGU;zfI=Be6aaNvbEGINe;yO3v_=8@TUAj48A`~84rmYd~Zbzdn;OFO>ZzPb;;Bt zAy-gV@J00FJO_MuB}8BGD27J_`f9xaZS|-uMl4&4NT4C$7J#nQd`w8#OLAm|lVJ%B zl=Szs^avIY&#(k|EtCsaGn*)m5V*wue&OIeOj6+8@~DBkm@Bi5nK4Rw-a+#jgSanP ze<%dqI!>tx+YETNz}^;h@_)%$yjT5S))?b5OT#Q>N~HsYGy?B1Y#HUDg~pn5%J*)3 z3fXKJqdb1COD1c2RrF(q0r3`rZl~2lhN`?Pwlfxvras((vV3H(Ygpa~8;69#I@_s> zR}lu9(xEVXx!)%S<)tI(1X^L=pLEN2@poHF&HU<`wdT{0CcrHR z-Rs%Sm^8v{x|z5PXZh^jrhojhu}a;EhNc3|gjf#ze;#9;`nU|dKHA-ViC^pDQV?Mh zpJZ<9FUg>)BK|n%1Kv+t0lJwrG0|t+=0tnV^F=A2>RpR(Tv=)l2$)hiQ`38ceuaPR z9h;-}*(FXw{x&3XL;!oBPg4HndQMg;Z5h!QJ`oy-w-R)Hg~p?MK9ZRzE*K-`CZY%E zdS^x)OLHWG&*iirM*jl>^ zLAOz_(#hk{Yjy$hTMN2TzI?xUU>-3CZMBx{9giQ9kLTYoAn-Q_d}R{6t=?PRrpmxj zuB;X4;e5XB4I<+^(h`w<{l5I2G+6=x#u^{2Yt(`6h;xOlzi4r8x7JDDq*zE*y6#|f zgl)n6Vz{9GPn4F~3tQ^5F5bop{?l%BI=}l_G5KjF?~RxOvCHBuqTDawI9U(6b^Cu` z4@=<-2;_ihp1M?PSfXpzM>p%fC#JW%+D!!Q2%kaNq6sdG>ONrtG) zDn?L7iizI(1<1o6(CzA{l}gNNS4f6<_NEw0_gnp-$34|WEH;-PX=Wd#<}qjzCYgho zP7^dI#@eOLulKto|8L)&fmy%qa*+kyA`Rd+fbQlw93r9VLbouj6@)#;Kh>3$y@4|8 zmz4)i?0QKHuAcN4wNUuYQOHQ6-ctR~W~wL-JudQP4G41yCwTBfX`+DJ2)YpmpHL6o z%{?TpQ`ffrCiKW@X8vr(Y-+9;!&A6zXT^STELt99J5RMnU3%sr;zajNG|BxJgIg;2 z{ozI0EdmX2n?RQtbMqOUxxntYWx}*l3ugnFQ-4*@9wuMif`zE5pjYA48rBSjP-^xP znM0zpH|e~TfC+PFU|i@CJ+6=ph8A2GHiPaq=LI_b$6+eBPCsU;8Ug*By4iU4=@s0H6x~(zv+HEL6>+%~i>Rn!KR#7v%!Tni^*lyWOCE&J$uG<-#cWeIk zyYw=3yFynLGZUK+nW!y9(4t>H;y5iCQ4r%`Jc-H^-N!(mVgIhs+WglG^Ac8qgYc5< zxTPP8`vABdpsTYL?rd)Mu1T>_>5V*~Ep>VY!hu|P<`FiQuSsP=JeSp3MAixQ&e-OL zLSt94T+cWgT`yP?>#a^Zqm?qIHV$w*LHAHteGaO=B?9&y=Au?hL&fq_V*ah-)DgAq z+9Lk||D1t2a~V#Y1(xUFw*_o{EeKM@D|*%z`cFgmxgm@w2JC>_1-g(8Ij|~xHDp1l zrv|*pJ-Y!UiA~ecKGhz=7p+mBx86Tbi_GR!L137rWP3k%DF4oLhD!Ncz%#D({&!XC z{EZ&qc7tv~9L&9nY(6FS@PZYi1b^+OR3WDe^~?CEW=Bh}M+UdUnb>%+XK20GFfp35JPVZuh5&i*6V&K6{wlwb{&~gp}P(32<=9s~K(_YZk9HqT(R91;iQT`?W zcx{I%5OOvB&MZw`>MtoCeCAPa2X|5WA`VC+Yl%1!FqSmxPr_%6~Yq* z7FOXm#4O>2!EAJdhkg!!W8?+B;F53eRS4>kzn?L=fcpUhpv(0&yKs{<>oabWb*?qu za@oE;?Xm-lW7EM3L zAn4YoxrtbPv!1x@LsPfKtD4bM%&o+nHav3CrMqDwdktAYJ(HN`5$c{5^`56IRY2B@ zSxRJ_diDGV;jJWON(J`e4T0`p5NU6QLELTOhja8sbCpvxkIS0PpDa9o&`GzR6M5OK zS`W`l8{zfu$%2K1R2$B#J{YZ%d<^$E;1)OMI#fCbp0i=l&DC;FK<(v1_?T$3+EIhp zwLYmN%=wo@xjUVNF!p^ljV@w{d|4DhmbxF4v#?!@9W8IHHZAP)d$UG?XCyM81i&2u z-TkW**5VMMg~?Zys5#j@PmOmS4r)26S91kys>=iBTV8>T=dQ4Q7+5eA<@$s#a1_I9 zkep61a<*2Q<)|%DC4f5$x-e6jnhmQ{yXcmUCVCQP(;_U**Pn*?zU5tOzpNDZoLfQu zksf4i`mPu@23?y5Rclm;2@zEM8DFW&J!=bOggt8*8lz=GW0*t#T^71AzZZs>shQBe2 z$;xqu15J2RhV(3c{5e}~j(uYLe>ePnH!BeW+)2>YwT?$wTu`AuQEFpNEty7dU{fZp z#X_L5*$Zw;6bk&thU%Q6&PzSbaTWF4kG``sX11K0!m@Aw^5VRzg183Ojix}iw4k=} zU>fJRRQSKscr)c}e|{ zQ_Cm6!gvhv7^r$Tv0@5!wqksv6U=DS3DA#+e*BZV#cW8#C1$LJiv!1pSlHXBwW=cOmf$Xp}Tm7Q9mC>@ocX6Z_}F3{sR17f8Wc?*DaKz55|{ z0r!K<@(a4>`JYs$l4!r*D=Q^p2t?q$fPX<3i78tUQ}sE;i8sA&VrKm-8WsYUrz}0^ ztbpkZQho|XFM)yLtmTQaGV*kGLx_L<_rW`F?;?Fxd4n@L&8=5(JX-=?j{5^PN(ao+ zY1_}#JO7F@f@)=sRepbfz5202axEm#B$1n#M#)nO10_`)yj{2wxOctTYt{7EtAjny z`SV9=u&-?ybW_xr*y@r{#b>s|Rx1?8*P9En>9*=PU(J#B(o^ZB$|D(`wEBM}Pk-;Q z5gFT>6ove`K`p7JS`$@KinOr%|4r%t_3x~J?qr_GvBE_@PGXKvf7GhPciNF$d11TR zEhj+?X%m{zd#zz{Z-(?J-Rv7NECikrFE=Q`*!%n*I4XlM2 zwDWd1fEJj}L(2+jT8A*yvxTu4rmFzrT?gIpAyLw8D;~SnQ5|!0$@bZ{8l_PC(IukB z0zOR)UX6>l)(ayK{iE-M4$8^GDCmkewF?xiF3q|YDt@8MUbx`-mJQH#pl=TJ{adA3 z`jMqZx`m8W{a;>4+xaTny5^N~#DdWG-^F`-IEF*hv-~aX@N1@q|DX<<1j)>45z2fG zE_y5%fOt1ScW-w^`O9fCG;EeZTj{@(c8RJLlhwt$*`TVs4^0GI@GZE_;T)?E3-L?6 z3fZ69?+KR~BbZoXXscawT;bvoz;SX5bVVVql52S|u{@Lbzp+h3Qc1?j&B>$h7$IwM|pU(;=<6VB|WA;3)GbWA^X0OofabPcomRo}nm50cZT zn`2RFv-z=wbq8JL^S16#R_S_-2>fdix$heWn;K}K}HQk zc-~W;f^>^`%QNL60d3@WE3!X#*_Rz;g-r$GdXHNedoC8ee7-ISt)rp{udNuILEGv8 z?mp<2=84tGCHpfIrd?zqsLsEMb$?14hh3}W*9V!C`h}10a_ku!Y!aOp;`Pm`p3i&Yy^Zdy)mFYj8Mt7J% zzNmRnEayX&h1z+}kdAMD7UqITu-xqx-Zdi*yAvzytJXN zCZ5^MZ^!DZw+X7hysS85d!$6@RR1wXM31!agXfR`f$jqP5a-vE@#UA~5JLsj#hY7CXe>9n^pw&A1$w%2G){y`8mmaY)7H0^{O4M-N62bbI|pV znvU(}N#YuA*C&#oWm=?_D%i3MsGN$jko{yIp8B?dX(zUHDo0P2-KP{eGi7BY94-L? z;ZK4=(v#BO-U+U=EnuCnv_Q zJDX*RAucMCl+g=A$Q`|CF7KU3q6>$cgvX!2^Kc2e3tnj6Be(b5S&b6HZ+K@vou(a{ z8F=;gVRuGUh625dEW((-R!P4IDZFbwg9ye)Q_~XpZI3*Z9NLUqA(j^W2)I|Ei78s(C#6Y}O(YX17pisiX718uD2Se%rBoN{u_M z+n41zbh(1d_kep1x?}%cQfI0ezoaR(VaCD?JtrebqiC)^i&XCY@nVnW%Rf!}Dh-cE zzohnE8Er=58ydl`S?R%VqDl@ zfL`e6FG+$glT22=U(RN>mbJs{DiH4z=+^7N>z~y}1@+bwbe$~ch^OMBu3@0_uU!aj z`ItF*)os!2lB*LRdBwc@?{~*{&|5T$#X~6&C|o+{X>?Jn3a|n98FZUiY6Cp zmj5x(5l10+&RkzRHkgLOo4)LH09Vtz7F*<1CRbZj)h$6AaNj_eqjhfD>txt`{N<_a zH=9@HWo5Sb36i^M{r`u(vw*MS`1=0E-GjSp0ukJcySv^bHzW`vH^C(ocPmibrAVQ; z6?Z7^R-{n8Sc?>Szh`&$2`~39&(r+-^m+d8d-KWfv%BZ)%$zxM=FFMd*}biEM)sI| zHu0O59uwbRPMXWQsNC>_oqmgRzggxbcLUeV8&hq1?zpFYm+Sm8*~N2>E4J zoA~+SFYFs0?nC4O3Hz@SqG!FYz zFaI0kT|?jhPDk-`sev5->YubnKrqgfKUZ}BSGD)g+%IhuXw%E0=NC85|C!QVrMNWk zU(C&i611=4?G~m*JO9L(qxHRC>fJ*}|4Y)Mm(!f8bfludj|G%#P zi4Kfs$GO=k{;xha{pVUQb|uN0c^2SWGmoAAT&ey&H6Z=`w-tK-e#4RH*U|r;HE~Jp z(!f8X0qHZ*?;*3;THPc1bFy+rUC+ymRujF12Ze^o^}p|~ zQlmDmfJ*}|4Y)Mm(tt|?E)BRe;L^a~pn?DX_16FX68;7?xUz6*z@-6~23#6& zX~3lcmj+xKaB0A$0hb0`8gOaAr2&@)TpDm`z@-6~23#6&X~3lcmj+xKaB0A$0hb0` z8gOaAr2&@)TpDm`z@-6~23#6&X~3lcmj+xKaB0A$0hb0`8gOaAr2&@)TpDm`z)=IP zS7RJ?;-a`T;L?Cg11=4?G~m*JO9L(qxHRC>fJ*}|4Y)Mm(tt|?E)BRe;L?Cg11=4? zG~m*JO9L(qxHRC>fJ*}|4Y)Mm(tt|?E)BRe;L?Cg11=4?G~m*JO9L(qxHRC>fJ*}| z4g5nIn6brTNnx=>8^yUcxf_~r9bFo5X~3lcmj+xKaB0A$0hb0`8gOaAr2&@)TpDm` zz@-6~23#6&X~3lcmj+xKaB0A$0hb2;Kh(gk*KxI4KZ+MmJ0`7QkMQ#d3bjXCgM&SS z!~D7h1O?kXnn&1dm2!EN$Yl@eV+#u?mdhuXH8`kCXjni}E!l^U`k!1(BS(1(r)R8R zOXhMt49MRMb&t?TX%vfPrlQ5?dbFa=QnUnI&r-D6ik6V;d5Sg%nxsnvvMAaDbzfqx z9}APeg^HGh^XH1TNYSJwFBEMtG?6VC2voFX>b~UA=IYwAe5dZ?38ZC#qODZ4l+b(? zZM909O6~*lw?@%YbG}fcSS&v%S{kkwDcV|S{9Dq3C5pCQ-ItE*Ws0^z-RH*jcZ#-2 z(b99hT+z0uv>CWwp=etbEhE<}6>XcMW#W33qHR~S%v`Tlv>z2s^u9sSb|_j_t~UZ{ ztDVsJw`2p`f&A@O_hsk&M~z~!>{0jS5I&H!`_z3oIX?*GZ$C6?$6VkTkiX;5MCG~V zTnPM~Qfc#WF6D@goL02FoWBy|;_r;2<>S1!YV)&-mLFPHb>BHfD*!EQE7`qYp7`VRoW8Jnkd>sMe~GK2AbIQV@31g{G77q-=Ik!_Xg(` z?I|?L#s^$dwBMnLDocXPiuOjOEd_0}qP0Yj%5yG%AJlziInSkN z9~G?}v|A#S{E<*j%Y)mB7Dv%4K>J0};woB2Xm=G&JfWOc0uexLIKHA)<~&l-5-3^~ zuJ^072^Fm>v;&HkNYTE676MIdFflX{zZ!@OO>8}>y01FtIiQKHCsX&;;JmP+rBL_P zg!T;N0x1=(7U$i7{H0Q~+MJ8OmA}-AR)_Q4s?F0VT3u*TU$NJ;idK(vsjtw|DO!Eb z14t{j>85B6IKK@|Y%{&0HROCUG_k`Biq?qpZxt=0qBVv#8=CxOQnV(Vf2U}fp^5lS z!B9oZs_ttBZ5TAM>uieFoby)D#ICbLlO!#G)J^Out^Jk))ip>5$@{)#J_mGkYKOCKx2QL^?0KdSqD)O~)?b|_j&Me~Oy zepLQSDVmM*ci5l&l~%L>&U*mqCuJ0^3+I9AzOsrI2(22l>Kw}{S`g>&f&7(Mw62_o zYZQy6f})8ncL!qE6`_e(!RnfWrLwv&gmdv7@>fOCLOCxgjn7|IMGND+n4*29Xi}!s zL+rnrqDh$txKC`ex}u5wY=qW?V+}>Kb1r>BY_6uFiA_mK)=bbq=<|s)9fDb_0s=2yvAm>uHv{ege(jL)3WR|vSrS2QVxyUTE z){6Eu=Uz(pZ4_-VG!I2oE0|B5iZC(XDqGA%8KLO8x#N-l#OU&I3%%SoU zYcBwcz!Iq%XJh%WZf=l2sxB{+%Yv5;a1Kb2M zpON{?TrdyJ2Qqh&xypR_3&29K2rLFmz*4Xbdn#Degr$fPOuB?0eitdZ~zr8Uu-=n}TMb9Pp(aKj05Kf=-|_u!1x3^mzI_#|z*hxCA6lUJo{ajbIbl3?8DJ z!XO$9=XwN)2491Ipbzkb7tApf1cD&Y705hwIamQ?e!2?W<=!P6^K#4wnseR)v;-1w zdxKJ-7{~>h0C7lhKwJ^2kwImAS1W|&Vvi! z61WOvOg+x=1ULy!fz#j&I1A2!V_+YUxLe}vF2EnyKzz^+v}7nZ(8c zaX~z=3f@{Eak<3dc|ksqAGm=uARTxNZh>FG9dHjk1QWp|@C}#-W`LPs7LZta4wwh# zgN0x*SPGT_iK~}`6<{U!9;^oAz)&y}^aK6D05A|lgF)bH&<3;x?LZ6A9N4H!0O$fF zR;~x?g9e}xkXTt_V=v$hd_XBs8c5t*9%Ketz%A_cHuweH1;2v(-~o6D9)ZW;H}Dj^ z1Xsb&U<=p=B+iw%b|=^ciqHguISv7xXy?wLFXwmB|2-gc;RhfGw45Lpko6f^kCFA4 zjX>5?HiNBT8<4dSS?7>-ja^_jkhP1wU>}h6i38vuI0O!ZBj6bL2}q260-OZ0Mj>kw zvIZe*4zk7|YYMW4AZrG{BL6+m1G#&GpQg{7HH5!E4YTgo7~P2daVUpa!T3YJu9I4yX(2f%>2Ur~pcX zA>`Qy^aBGyQS3%y@gkrg_zv0%uoA2S6QHdDKZAW>KiB~VgHFH-T7pd2%p2OPEyp(C zDo^TSRqz!k35o)DkQ?Ly zSwRNS7`TB4$bJPxP-Z09%Xu)6brXrYoD0Jgy4}1VJDK+y?i-4Ipb7Q-Q2sECNfwFfanN0r3q z2Qv5f1Z9ED+wY;5XW#|+9b5<7K`3&Ef$pFdddLqxa{d;)1iyhE)FTQU=KLU#G;)6e zpv|v2mH=0MH-EnA#V}`1&7qE9XG`s6R(5 z=m;b>ZVY6sXb2=8XaX9620-GY`k*Q(34DMz@B(YeOMFaGAaxdhD}MJp=MqXDQf)T)|+YrtNgRj9L5Df-` z0iZwV2l|3OK>SKCAnhxEJvom8L&0z`4CtJXA4hXO4on0Sz(TM9Ob6eBX&^nA3cdl8 z!4x32Js->iv%m}>b^g>AXLBvKC;T};Y;i7-w1OpI4Ojub1Ixg2uo{Rhe-BoHl|b5I zJy-|sfnUKzAnkAtoCU{04e%5A3LFJTz+rFz><9b6Ua%c(0~^6sumx-eo4{_c3+x0t zKoamHko)C45!eI7-i>Rq`GepPr~?APF>n%`0H?rda0Xlecfl=i6Z{OWfvey$xCE|% z>)-|u-fi#;xC7)q;XeRR!EfLZ5S={%kAcV`wkUf31N^SeUvqp5-he;BJCHPvJ|5-b zDCZInCj;?89Pp8Q#9_w+GN#B;?n?p^gG4~ePRLQl5uq9920bSO&VxY$J8993^`A$&gEM4A+!w8B#qEMO(S%nrROMg z$;U`9>5M!xL6`JGlXK&C0oPujD0s>2C(|K`Q|AgFHa4^QxoJ<@_G^i%tD! zHc^~=#a6|(JUAEIbLUtLh&{@+z>{k!zY537pdzRM%7b#C3@8msfwDmQkU;Jcnxv@& zj5G$#;D1j4{N8$`tqbaa+MpJw32K1qpc?oJ{8xOl$R)NYep`;>x5SsrwfJs>Cg%pt znCl5o>_BwUoO2^x6VBy+Bkz`+%iPe&TgC@tY>@e*abIiBrM=n$kzMj@52Rel(@107 zFL}y+hFl#u7nwel!$>1^<335(8N5gC4?y~$AMgdCAP@wBESvUT67z&I{vy$wTt${z+Q77CDUj>MM2lx3tfWd6Kf zpUNO*MShk>>LPw2F_1DO_TNQ)KKI$Zpi7^S{v~}xVupcWELZ@BfWaUd3<6(+?O+?2 z1mwO6KR5f z7K24#K9~pQf;nIo_y!CGhHRrbm-2@JDO=LT~b zwUI{XlY!`CCXlkGfEi#q_!darrUK!KJOa62j*>>s4S7X2(SzjatUdCblI!Io}KRfCFGZ*a5m= z`v!eC*So+@Ahdnp5ICsL<@zj;apnZaI0McB8570# zUf}#ZxCF$%Ug3Bd+yXbj4IuvcXO7pwH6ZuNpYVPIPrzgF2s{K2zpWsWf)$Q)xZkag9|oDYX8^}h9D8t#2QMy&17!00 z9NK$e0q?*o@CSGa4nlsx@plkc9fkfUcmv*o*XlekM}scs!WWf@B~87zr;aM>mf093ml*XA+4(2~Zq(fWko5q2$>{Ay5Eh1hN*D9>`i$T95{$ z2C0C=GATKx0Lj(0QC2#xa{yV_$^>$$>zo|3gXN^n#xV@kUj*0Pf!KdIM?3K6yt`b3P!Iz8L6^Q11iFB)xen&omt#-Rjq?By z1$uMcmE%B;JwO=eeKAn87@r!##UdJ+8^bv5*Alqq@~M1Ijge4zY&-j+uBhCGs&=u7U)4JMLyJQxkc z*GT+2lJgN@C=mOIgeLckZ4BdD`iR{35{UgR0ttcmOu2XXC+Ug^ooliEaU7+Lu^c7+ z7>;>3N_paQeSr8?H;@d-+*9(BvPI4bK+3zwwb=JJTu%bQpVB#>38sT@!Bj8>NSbLJ zjWKBk=X1d06?QXPo~4egjXyV<2PCLyn@? zqu>ybI_>7T8EgW}!BVgUtmpn^9KQpS*BY=2tOP57G1kg>`@Om@&#}TMyw#j<0PDdz zuojdf-!h;ykopVVI0|3R<^GMpNMq29dqv(|U?NS>F#b#Mh- z2B(3HYo|D#1jZWEan64N$G{1Y78vd6Aj3IKr$p0%4StX6!Z}8<>WPSi1f&WTgOG#to^^`PX z3<{03jC0S` z>4(ej2a%hIT>=(&WaQ8+VeQ75dp?;SH%>{Np*_j?w5D;jntE}+^est~<;mKKWjrfI z#FhGZmLfZA*BE2O{(!jmUOBW!ccQ>Fd>j<0)Dw zq0Pf3x19sOeRs2J+fH!G=oK2J()3wVbx6Ys^IJ$74=>R{m*6m8kvgE&*e6-qG_0Z0 zcr$AAa!!Pe9?nH^TM`KfXtlQd2l z;fUvuG%YUOESffFy*_YC=sNh^-s0=_h7O#xsmMld(uY!!+ro{5uVl^itF(fThmXi6 zJzUDE+NpA__$y}qrg1cT8v`dfocFEDi+;Gx} zks?7`IpKG~koSzfx+Hsq?`p%8{ zJL|$U8h~@;{zOYEn~@v-%*lw^&s$S&=Nd zOx+_-yk=(UC7zrl)U-4Pni@`*a+MmMwZE%PIpW{o)Pf_jrON!+qvW@(#Clcxv{z{c z&Ac(~d6DaX!ZG|CoHV4FKeDv^%(+3^oEVjha)vD^z8a?_KZ(AsWjAd1swjP>lZ7qZefAkUMdY0+6-A*VSkqJ z3%^&&EdD_C`U7x8qt^2`Pbchmvq=o+wBmTbdeDA#oMnk(IOe(iLLrz!bd%dn23Ak9 z`7LQmA~mu-h9l*;g(mm%p8whgN7+s-6fLrCd$%G@WuHY|v~n~%xC19EoWYHg8;noPdEpDnO=UVQ$ejtW(h{{NA34WbYD)ig$lfywbdOr=|CE38p^oxt_d3fuj zjGDs1u7g4YZ4p6{_B1mdWX$yQSu~2uw7)atChe0m?yZhZo;>+v#0U%ZlcCXaXw6sC zzwKp}ek#2Li|-j>4G$--+BfUc@q+z&VAoO?`RhYR5U<>3=aU4pu0JjmBlQV5(x$DN zoNdtI`Qe)}Qpcv8S`1iXJJ&a^Nafdb@jP<#)@3t~Hky$}dP!i(PD_dxdpw0Sst0#~ zBRcs0>b6I@?ZvXdQLP=I(#*{tU99L(o3C4(N)>%P%6gQv+=WB4M%Uf&@y7M`HzY<< zecKih5fviq^-4RzkrhE%W^oELFktRE7%8y!b)hqX#-EbJsMWb%GJ;|-lm7J-M z`MLMj(s&XKT9ObfOKblTI`wO}q)YO`5l2C8Q{jm1?Cf6f%Ab;(h-UddydXidr7Qk(R5m*U#^#f-fY7rH_czfmXYFK(MvT zr-%KhSZ~3o|VmNjLxsLgM~!XdYJYnGb36-i=vm4CI_4seV@*} z{k-lUq`}9F`5uCk0Zzxok6#aNo8zS>ftNU|>u{tmtc+V{-H6;7mg^j`>)+r=`wVS= zsPmxuNgqh;LQsPQPAo*)2aES(RwAL@{&_#asU2dk+x9$f8QV4Pa4?w zoWwgaGs6~bk$6ixy{ldBZbM7AdjzMHu7lS|AUe{=bYT6 z@f7#sX^Bf05$k)JnP6-7U5*@%%dhq(h zD=ig|T<8}!PID+}p+s_&+@fEW>X)F-y2s>3hm&3(4M+UWr5u@NSXX71*@q`>iqw&I z_fP_2%aGQk0@571uEk;{=-i%`&%GsSWUQxi_hvXlp_cIvZ!Iq!{X`-m>O=Ro^tRbU z!{B_p=ykjI^xezgNPQ?L&>G<%XpOWCT^P3Z+o`pZGG^fmM59-f^kr*IIyHFWw=-2a zwDw~-VpaEh?;pIsaD``ZRG*8Nm(^A{`}SWemu~%=vHI+tq0y2LP60RvF4UY-wA~Tr z!J=v5)P+Na(bgL2o*mwlVT?Yn7fvu7=?l+_-C6Uj=~n?Fo1SL0;#@yd`KMP+vN8fn zFequ3!zo0X;yquDT-W6dvjQW{X*jvy%t_QQ&M~h%M1x|7lIA%a=|72zPv6ZwLj3h5Iq=|EM39U6prNPe{fd6+20n% z#~U>bS80wVozo=c%9#tbR?uv85*)FRPGNUTtX+P+v#x9D+;bG?*Zya!S375=K3Z$j za?9a}B_4bD*lS$$% z;V9pGSd~*QV7YyA!H!+w_~_%0Z&)vz^pfniZ{AOOEMlB0M|!>EdWaeU{Q|?f1^Hu+ zyGC`$TDkaEtsKqX{DRzrLIc8hcQ@I)u8+P?2}k)}f17Vq7s?qo*y3|D%Mppi#JgaL zw$ScTK@qlyoU3|F?dSok zW>DqS`u#?aoOj#i&}!-}?jkJl!{Ki$%)iy(Z$r%(N(=Wd@rkCGHQByTRh>&m^J3Re1%r+&MYwn zo=PT;k@m2NNYZ+Gh0gjjC|`5EH)1-Ls8IhPzaZ9hj|Egt?3Gx?VDb`EjEV~K=LSpG zC-v)`%%9^ZoHEFUMte$A^Oq=oo&KB0RS-^Tyd_TlbFb_cr-**5gIA8>bjR&UJes*; z(zvA(^%ff~q5Jr8a8kpmajW9~?Xzx6FA*DMoSUOK1IDjAmNR7*u`0#+UU6FYeRU_@ zz*XB72VL(_oJ18<{5)z=g%XNGeXI=6(t|I(8t=b#-Y?>>%jl!#ani_0n|r(4uZ`|j zo~LoNK1bixYLl*UHg2{y_l&lIUKq9%ska zADKlvG`@<2thSOU_=I`i%t$#GA zvYNG98PKIoKaWskz95s@k|p97)O*%9oibMTy_%v%3?~H~8EGdLZ#%ZYhKglVo3>nP za`Tc#utd_hgyqq_pKZ8!rSkRxVpZNAW#L?bBe7WLI)2IWjBIgPNsakFha+?6H)(9$ zKKT43vt3rw#755-RWl>|_aEP;S`p-?_be)O1CD6)WJ$N?ZLYpd1V;uSTCQ_3-Cu9L z)^$LR_1&kCoAQ>0-SwL8PFw!>PW2~=jYw3H7mvZIcreFcv_*WJuFl{m{o7@vU6o_^teuLvL=KC-GZ$>MS{VFdc9iMw!bl-gHsoX1pALZ z*f5||{qC9sS}Q~Zg+y5CC*Qs96a4$Qdh$d-qCv(VC+q$)%b`C1?W+;esDwi1s|4ot zak3gAeVYzsz8WzcI~7YjJhorTjB(Gg0w^sfef#sZLDv1n@6hQ?IC$k8Xh?D!yvBB- zNZCePl&<0U_KvjK$#vPGlKUELy&IzY5Sr97i!{>O4W{oXeLLxx@AWv5MzbtcxgB0z zX{&$p3b{l!ruAqiDl|MO+(v}b=Hc{Sh1`jVRmZZ3?!>O&q{y=&eU*8{2YD35-xjWo zGCt$he6_tyFmq?sft{@u>5X97Oj_{=JuCfY+Z8;)L(0)32R`5y8D+QGZ)V-|a!9v0 zcyh^2^mag%cWumpiOG^Da@S=Oj(N-%h=xQ5iAPpT^z*_66*WuLY}5`%=JlK0<1J2g zVy{Gdj5bbWvlg%XeknCU7I-Z^JvgpUjVc? z#(WZVQWcBiSRyV_+Q)GXMTzDlelyZI_AK>4z!FG%%HQ(53$`ac(K~gFt{vC7)BtGl zRXT{1otNX?X=(rvt^^tN0k(=~|us@2N?6+~%TFFiPp0n8@6LHO~Mw3RYw_=x* z{{4n`Wfg}Rp!QU88XRfUfOVETJ?`f?7-PNn;Yj2?Ji(+wSIS?xf`zCR^yf-~!=*mX z_wcusjIkY7u_6(~@>`4B!86KFm$hh758d&dk|0x#uiE7qR2Ur?9@Z~7D2njSlBwVj z>)Cl;jp0aqO&Xis&&rc$+q>Ys?;Eu1C4N+?#}{uQvz*mIE6yEDw+j+)}UzL1;A(>}^s zSx(nzi!+b%^$APehH|8)aGb7-X&k3gYa^3+IZoCSRR>B@LGRmV=T&}C_2#?wN;^o< zQgL!$Dc-SQ$K1baI?&2-;{BCNaxyzq9jIDG-Qv41xn}86FmoWe(MhDHNh;|Qv}|&; zp*8h-?9H$$H^r&dFWr3KjyIWa8y<<3pD;gbr0qi93W)JAiKNfu6hm$xa-j< zivBY|+6NmQq|)?D*kNYHF^h@pkU+D82%FX4KPVzRPtIwXv*&3#TH|PuU4Y%z!xkE8 z-#p>#j6&x|1ld|23?)=MB``@I7+Rx54okQrsr1i#jYQYq%J9~t!Bt=;D`?5xAtoOQ^Mu@ z;V5^x0*=U5qg%7T8$|j<@jy_w(mJ zT5dS`Q!2M@r|rR@UpJpNe+S zHOnp$y)9UNtD+f~Z0Hc6v;)UC)I+usSaLkxae7@%?MVvWg~d~gXI;I0e3$3kdH7&4 z@l|SMaH2Dmz8M+OI!urGP>!W0oYa)lr|@t0Pv+i?^`cHusKq>ulX5iel*PZX?jGuI zxfkfOwOo?fhm;P;jqKlHxt>+bE7`_ z8tSof{0d_iRyuf8=CsPLJ>f_zyva3m^DWDS4setw_YJmovx)sy?r^X~t7e6?`e+tk zl{DfLD<{7)u{k1H|{mYRB&w*2MDfn5Aled0Z-7FsZA z+E4aI1S?Le69F@}y&L?3a+Kbp;7FwU?b20!oA$^e5{O|Fi<$H}tSUA>-l;}4U7Ki> za)KJ^?PIq*JRkIQeqv-3&xeILdU9i&W0^#AW6Mj9xzY56ZGo1Cr+TKn^K+FmE5HxoHykTJ1LXUcAGUHJf$LZ#MC7VsG?qr)e|^J~q)u z!132Mm%sF`up6zaZFe2iawz{G%_gbFA5uX@! zr2Xsc%X;yAL4qe-qUD3)47hixc9VlWmv>r*LjoAG&jd}BrH)A&Sd6_*#EE1!0NZu`@*)eJF8o}Z!4nu4|;RDx}q6^ z`K-Dnxk-HBSz-EzxIcYkAvZOjbGk|ZkGBn-Jw=c;3`-|+lgJ^#}K|B zF`RR7WY#wMZP`*$J;DygaDIU!Yn_SDC-~W?*5JSx&NIa+I@P<`_|6&8fl-cM7%Q4K z_STc60VSTi_kH6l17s*^lhZQCGS&5Yd>XVcQK zpH7}C1_$}lD{IcZwtPXxZLi_TJ}x+W+UOQyd%vPw_Ob(iXEl%e^G6>YlOo;F_M0EZaOS8qzuf)(Uj8yg zyT@=&sWdgG<(s+PIF74c8F`N=`kR&?nNaq?Uny>mLhGT_8 zca5&GWB-x|JG-5Y;Y?I%=J~ZMxo6w=@nSf8;CPUx&|<#@9`{pkh~fPIv+KyQ*E4Er zKE!b~f^bV*h{b%blzAFI_ilaU`TyHx875Rd;uFCWX*Jh0->qd{j`=RC*hpZWTWlow zfv0mBu&TM15gQ&Z8zZa7vOdag6DMz;sCT-|r8b{4nU7|Uu_fz#S|k)3U7PQ6GuK;e ztV*8o``d#par$JKUZBF@9OzBrH)clWdMlCd|K2m_rakq=6MbP1p!t5j*zDSi=DEAX z%1^3UFQkv$IbTW5Q=!=CU<|oQv{AnN`4^9`T>X*U2%VhAy^QEuo2H^$Nt9M2qIu3G zt;-YP8}kKoFJ^8BtI17vA^H#7SZCRuP$GPpfYAtF==J6n5*v-iMsMa8Vy=VO^zCB2 z+n5gR%*fd1Y~j2~E6_f&4InmKfH2hosZBb?upvGf|G3@jrr-63)^iKh#RF z@BJQ40#BTuWn)*}D{p&OZqJn9i9f(m`{T`b&L1O<8@c7r5R#zFt)1y((%gWP3C^tM z^G_e1SBGcfMsBa+h=mLb>Y6TD)eQ|}ILW%{Y3!{V6bUV$?MqV<f?{vPmNj`_h}5L2^<+^_NS{@yk6E7U&U}@Bel5%vC)osZcd&E$dd;w z#5|2T$GoQI`^Bb&=zFOHg9m3!@%!6zF?ut%kaeVy_PO&R$Mqyj&&-NR6C3UP&)dO2 zC3WLaec$bYyU&JyxH9TwjNZ&!&b+l>l3OlXq4^Kx2aH-bNuE6X3q9Dp9P>UG8@-vA z6B4HH_-x-{#-KXsTAqoikGTXxNF#eeLo!zAHDcgB*>9}`o7!um75&i95`*d;-I(jq!EoSNcruSsIl9sC=OCDg(Hz_ z_H6G5PF()$;g~dQ;D{Y0nl^vvQpK7FMRN0ksIGOgd^H1RliSBkGa3G$5~rHD9M)y;bf3B18Ww3@hF$V0Dh;iD9Zp6# zZdFTu6}9Jt?1z=!h-|+r&Y(qm(_W50R%W4!lf0*%TY|Kao9E4}Y4l(Qh8%FDK2MWp z>>7CbZ3C4C9k|009kgEA{(0`;re`${E#zbQ%e@|52gp10R=+??p8G>b?>IS?+~gIP zFZQ32O15TxDbE+3)lt`|HvX9R5~qDzTb?xcF6KV*Z|tYEkJCP<$rc-*XfCx=9ccco zS8sj9c)DrCgz1Uzl+oH$^Ol$3xY63@vhBLsZ2dlY8&7&8b`TrAnMm-();95$SiHG* zOv=Ho&C{6I$J~>b?5p?FZM_~exmfdkWlcL;pEDWf(AzW8h)1%Nec59{tDy>07>@MQWVgycs5g0{@`>UP z`ol>LCti!5qwY@4_J>M?c1*l7{dBAdNWUB zqEU2Ul3VH6`5lv9j}FYoEOQI_%YGE8|L5!TzgYtF9&Fw|CiTI3O=5Da*DNOYv^e#a zT5mM*V&rBXq5QqF{Uf=R`qH>y9w(a1X5Q;f(%`F1y#E(HY>?e5ABwc3yWW528Naf! zzgK1wXd1YKr0(1X{)Fy5EMO~ZBjOcTDhw4w^Qe=4D z_UV`#{ncp32xubP7wy_aHgYqcmpIk67W0`%K>L{6fw=@Gxy91IncJI542uqC4%6pz z*=i2zaqnVW-c2$h6qA?&+01*rc}-2ykei7eU_0h(8zy@DVlOcp7fjY_wD{VjKJ+Z} zIlB3*+FWY$-13ajqrv>vs636kN6e;uWG#SR;sr;%%ffSq3cXl+TKmp|zLZrHj?50{ zB}3NFytNq;Y&}mbFeIQoeT_WM{t`tx+WHA1ikjOhX#spi#$nNqN@_ugH_- zSjaY%G#QXBq|n=^p2rIJqa67z0d_DGjzr!^r_~?&ZjO6uIO_e=C2(ZTAz6<6-PEQm!XDE(uj|zK08PwD;RGpA8Ob=+i>;(vgV+D zvCT0zI9hg&9HSiHV9_UEvM$o#rxTY7%iAil1A=nQ_h@z>txI6}ddIRuH6!GGGkJ%Q zG=1U7&V)rR7A>ECw5=Z;K4>AF;c!GdD@M;B_H~L^{%~ZD0muA3O2;>p4cSaqTgk1b zU(X=_$Uyc`=1rE_FM&J@m2zkWe_MbxDmc=S?F{_M=BSUNz zPQF(hTKo4gy43gUEWWv=RkY-$YD$X8pb(p-Rk;Q+-UKKD)9r_bkFHJxSo@Y~xX2d!W za~H?#8h6~YE!ClUob0akdSWhh?MeEY-LpCkJ1kFLd2oDmpnsdLGaT`j-<6#b-Zb;`xiOqbI2qww zdN5*I-bu@Tis6h_xy@O1J@{?s7K>vz3*pF<{1(aY54E-FQ!9qEU2(E!nR|c5wp=-4 zIOpJGCr#DUKkuE@Zb|PL&T}~86ARuy`qSWa4MxRq5>M7wFhUxZO8&LI!H5`69>rNd zbLWMtcNflx;Z%Slt#P#F)SphD{koH8Rhq@0pQ?`w(?j>y{<%lbT$=S_B3_m|a6|{+ zCcWtKXPl57aMagg%%ACv&h7L|g!G?xs!gmdweEo*cWXV8h@{K~DlFq+* zc0J_|M}4Hj{K={tX{2XOIyu1iWTjLYwcO-~44mxn(nbs{qzGw5f+wqg z%>B^vTg{kvaDCuN`>gAj&aLLK0z<_{wbxj_@P1=dWI!3QkX19AY>rrelyO_RYbWpR z5*}zzy3F6sb*!n8##}aM-X9r|$+;i(hU4s=A#K^;={rN(<5MTO4N!xL$y+|OsiSOK z8iaF{?LW`WF^vcy^>N%mgn!dMIrU(M-d|sO6iV@Kq5nH9L;^VM+Hs$q=Each4Qa$e zy6nz7rN@=Cc}OEqMMz_{_YU==ybPP0uFA9GQUN&fWm54wj^9F*Xpl61d_0OImfM%3 z8q_Q_Gq>2N4ECOQ3jMo=XGZlMkg3hlvT)?JsMel#td4brWg{MW=PN2tq}BIS{diX~*k-qndR}^Vyc&MHwKRMYtb}C}xrs+_ z)U(LklBZUG(B62{dTZH?2LNG$LE-eXCCFeLs!37YX=f z5q@h&$u@p^t-$A5mlLH8kp1MO*`(488$R>f$#=u%!jZTa^W6tWJnX!Z6IZQ2k$eCg znds3zr&XFumm3D&PFr}e#?f>TWVhpFts(B;Kl1G~DAQy(n3RAB9EqYm%Ua$k&c+sPGQOyo>PIa%?Mu=L=jz%iRBm0F z9xd9#!KyS*-rX*mrqz254hWh3f|eT~+ggyoaYwrr;lpvXL?qB+m-Lh)HkvK(i{pzt zTgnq$(WrA9rPG_1qt(>JdcDeg!Friv*xdbnEqnJbdiMT+d|idg{mX1!f(k>OUm-O}sMfPIfYZo;b2 zo7R71OcjmBe3Oip)2z3v-8WPuDBC;prW?m+GYi#hhx*)RN3QhKn7z8fk&uhek1{Lp z4NbB1^~0O5Gk>MhP?O1MN6JYackRW9c1za8XvZ-(k&PEt(3_bAPNmlD&0IU?9LL-= zi>IcJX;hP1CNI)^iO((j@&rBP7ZYTZA&F%+oMhDW>7PC4mKhpGj3h7p35TD=;Tsvm zN{_xOmEwf&DoGBCX#;k5Zk;hlrycW9e7^PW=CbpyJ(_|xha`Y7BMwPrQE0*ZK z%B|Octoi2Mn1vlE#SLAi`^0{w($Ak#rW|nI=Y$o!qI>&63uw_p8X-AXw09!cZmcR0kq!O2G&@yd&*&Uus| zS7&2y5jN@xN9_81!NY$g(Yn%GO~vWa$}9WWehptuiRh($w#YK2Sh@tGN>rE)haY8=nvRL9TjD3bM5XHEWX(>km_-Igghh1; zw3Hf`^4iclS!D($(FQ%($!}Dt)k!D65Tz{MNjb{mo#du$)NxG+OVlC<$L}<1-i0YY zZ5rWki?m$N@n?_le22V|TE%aU-`<3yeSFjLTd#0vId5kxjjBFQ`l;glrIkkI-<hv)EkS_b+$oH%0!6sijhw~%3rJmT0o(K+8G#Lb|d8Ctn0JyqM$n`4s0beGyEx zoRcqtDGtxK!+g84fAGg;<15{-bBp>Yj+516C4tj6)y4(WUhiY_Yg}lj%tqbsbhvOi zY*zI+`gi8E*`djomub14VG;iFOFzw$rYl(|-L(LuR`ym^<(Bn)pAxNl`xN8rYtlYM zbF*uIz85tbMw;>FU?dz; z`7YI)H{%Dza2(&%FmlV=P0uanT{wf|_`ZyAFnCL8CBa4i$j5GJ&J*t#X&m2HF*x-} zBQ^b4zSx}=y<3;m)8ND`{wlW##eW>rpxTFgF}XRu5n|-ln>6XjZB@f(?icd3d=`_& z@m&!k%^1>%^(M-HrT#bNJtxJaaeR};NaOhakHJ|;Zf@ijQa}5LSB3lBj>&D4s?Se- zGx+@4p%Iatk;d_zA>oKdkC8^Svm?#8@4V)OT#QNMXjRO_wOOd6g%}*iHZ?eo?PG8p zbzpED`<%gX>~jXkvCkPC$Npn*VpCJczF_3$*cS|rV_z^hvC*5O^%}W3TB5;mv?_z+ zXb1nnVO$h@b9^_}TpC_Xb@U-dP0el8T-WB-Yp!d@r=%*RaPnP4;b{HT zv=tmZl2IRXjheR{J8nMvDyK{iWnN<5rjBElAwg{VoVjeVX*qN4nD>&{v}tVmkGZ{> z>&QS(-a&DiJ|?-){>TZp+wa*SP! z++x!{=3dM(rZCF!wfO~l6JX`On$4O#QO784MN=jpPWF1JA4iJSUJu7;-H_n#wW`?k zA9D*a@2BRiZQcszI&kugQd~LhGG(X!<(J!AH{E^JIT;Z#^F|+eV6q8LKF0bpRTi}P zb5=>&MWvpFUV$SK{@X0A+6=tbU7od(mxO~(R@u~Qk<;(HXlomPkejTfJxlUo#HLeE zWF<>I@l3Ewp96N-v*h^Kb>GcnZl-49IpAa?O^TU)+~$ry|1BJ~=J5HiL2C0kZG*_? zzfh=hLkCXvrfJ7%1gR~q`}xW`y~Q%5;MYl)e6^Q3ld;Rdi4N3Cqqz>ufBnsL{lL@7 z>WcbJv`DLOu&kWU4y)PxRJjo57_9tgPqEE^#mq!Ibkxu=ezPdj77=*!>(hQ?k0&O# zFYB6VwMlMpKK~ZH*4o16UuSY3d$18 z?$P&$ESr|e?fIaPBARxzH0JH&E}KG&=6+z`toWYVuWE z?Al4MN29V-5)m9O#{2nK;=kD1PJ4;AZfWjAob0@!_lVf0c3sxwS6gXQ=j&Cn=>6wj zegE6z#f|Hy>2+3iiK?~E^!xNR)sJZc>krBQp)wqK42KS!$cE<=+lh^Aj@FB+=_mZk zDH5c|SG};`pSs$1pS36IFRs_go>N)L5>DLx`tHs3>vq;JP>5fL{g2f=H^sR%_4vo# zZv*~>qb3Xm;K;M7ngvrGdRVKjJQa~=1xR3`Q8-bd0XBY$#L{lk^C2Tobe%yO_3IQ) zcd%-n&twNHw&UdO8?^@c>jAybc~?E+9Wcq`qgEeH39sPDo`va&&#XLiXV%YJeYEvN zr%wd5{cm3#)Sv%citwwM|5cNdT1~abq)yVPXNTq-a|vEkP8MWavN`YEVTlvm)nwB= zg_GPE%Vaon!jUH_=-O%j`A0{Y?T7SM=w58plRVeco~1tg7O`0TKQ)$^d)T1Ex*Y`e zj$3)lshjeIL&@f3MCVzxNNqmK#5R`5O^7KW#C7wJhxykdnVn@zBT6HpA4LG!$7=q)k8fv>8DaUM= zC_5lRdsu_{$qqTS+N_dt#A9$`7)Fq+A# zT>)g1HOLy_>9QWV*HZkOJO{+y%)FSFXGmB?7b`nA&i4*0Sn%Y4q@=-gr9R>OlC|hy zdU~&n&1%(}s^x}Vdt1sonXs}fR<9y&Pg`9W$VDEWnVx+499y2!pX?|_6$u01&^Pl}~|sHtyIsB9Fq zkJ(_WQ#`Mg{S@MM#E&{{Z9D=yE#jyr`6#Yo>C3YxcRW%(3lDn+j(EPH`h`}lzSl=~14%zE zW3k+YBQwei7Z&YpwKApt?ItZZ`QaP+rVhm93(q?lH2#T;rrXJsW_?Qll**i(c7U$yhS0}aV zIN77ArX@}!pnWt6>Yvf$kOXB*9sar9>OSaAYKm;1j~MbB$}$D?C}A#})z8ls9%;9n z-Ib{NuWvRJUsE6L&4$cp^*C`zqr{;V22XDrQy<3>T^rD;Y5~%SRb8uA_3E`IZ@-hs zLI1{DSvbJzoT)s zFxy2tybr;MK^mz~*LKC*{&*%nPdsH_B2otsYsj9gKX;`azQ1!AD>70a8BfiB?KX0_lw*`xXwUeEnh*(um?1WgMdod?MmmEEALt65h*w ztU=P`KWOD>b0){V$7n#4&93d`wpdF2bg$gf@9(|WVoPmxWtPfqX1`(y?(BVaQ?obC z5MuL7ypg@bZSK4*ZtwIi`-Imcs%o+!cp1ww%8}M?dGm?Ss+t~CVszcZs{PEJCH0Lf z{$~%58KI@oblv)#p2oM$(m`wPjxQrpYn{=_9t`wG8lPC%n|aHb>+P@jH={536ADIz z^|p))op^j-@7t_f8rJ*w_LA821=#_P5nBTC4!iI;)u6Z{o3;hrsUOuAWSn?Qqc51- zsQIrrn|~R>=c4XI`o270cHoL|Ml&L1t=CsnoL^VmX%@P6x|>K{RH5Y_O6BM642)4-woDz?1K+iT2Av^QY4U(@G5@j7LGaW>V;idq^i-Z=_K zB8TE#YquCQBIS9N8*!Dt%@*!%>mGdQ)wD0JL(%|Dw(jeQWpY=F?$KCVWnk<_wvo^{Xv5&w>O?{fj59@U?ZDxI)LgQRkoXrLL zhLn9bwCi%pu?NMOF!Y2F*n_wRhZ1}V=^#mX#}i-+Rr$0PbNX$5

ZWbBA2P-P&@+_6h9@NJc7Eml#nOrP;cHwCvK{_7E z?x*Fp>rc1E5#LO3V-2sk&{ADrSm8To94pr!%!UVoKepREijQ}S4x zUMW9B^8RX=zs)kFb*X?fhpu-V1z#+C%Es(#G7Mjne~P;9y=7yeCdZy$oX2%4_zk~m zbv$BE+3~9tzf6*{3l^-X;jvZm*IetFu4?tHhYxd|lKX@6Ovo@`cee!>xK7LUwBfrJ zANs-b_-1b7yZ`f^zFj6CaVwz5Sw28`ia^fU3wmKoV* zjdYvFwajxLuSlG>d&r$Xmvb$>{MV*O4tBkgq^BEi<4Jj=2ehs{Iq%|#99)Y&KF&Js z@!N#V&x$GjPTQK?36K8rw3OoCzF{4=rBc8T)w!1X+`iC!d*gsH|EIaL*>Pk?7V|7@ z!0=0WfLR$AS>0XLe`j!Q)W&Xm7$k$iU~u=}iOZ<_U;pWU{`>#&pa0wIfA~L+i{AeCzf(T=kNhmVi_ zu{-?ij>m2Xr*aqjd}^2HVRJqohrfULfal~b8xp^@a;% zt)>>;zW?E?!PS@bWw+CYG0Ik5bL?TTN(nb0DD1{Bjhu^oG&&@!5}2}BgPz5NP8}s} zj=iSiPfJ!R4(E67@x#k-t=$P(Hjw5}aHn0RtV98qes|?lDIo~mu~Yh{!xT(Y=$sPtaS6cGtTBlE*&qmM?T0|cWKnkGC}AGTba5`z4Ap=VXmOLjNG zIC=Ea?tTpYp&6Kz_iaOG$#m0+kBaRHb@i#=LrEEqm1bT}Tkf1wjtgkTtf3RUQvel$ z5Lb=_>J6Hx87L-FwW}=hOtl?!Q^|Ci&4(k>f@+k)@D$}aZ4`mb3w8DNrQ6dbU~-w8 zZ=&iF1iVw*Eb$3nW5AdP_!!m+(wZXP5jt6Mf%Bm>yepg#7b)Okc-Exim|LpZivtBp zy7KG9@pweq{J?**Y^*D| z%Z#86Fi=na(Nivqlkn~^QDI3u?%E}CwwBSIxnTNyw`@5f+;uKnBN~Vrx8~U>G><}1 z{^>-+9p!W1$Y8FtAY}qkifAudE7fEZga~D$z~$xhCq(-WL8w{RSTxH8vMk2jzyXRi zf!!i_BvjrDN-hiIQ!mpYe;Za(4vMr}hb=pwZs<>&%YaPwIQ-nVr{&M~`GZiq5f7Rt zouyUw-Eoq6Ii|Sx1+}8b_iBLzTMWnkFm&vj_RXq2w~czI?ATSEWhKUykRZNqcDPZWtHN|jbMK~-wwrD%naEEEPeXcDLc{ZAtM`y{BWd*=cCd|T-R~rm@bQXL; z5fBt{9fR6g$TZ96hINoe_PZB08@pp|eC633X(E&k3~P0Y?YzeN3)Fe^3EBt|pDlIHCg0@UhImsH3SK|mYS80tX7{!~B zOv0k4AKb{)j159ndpK{GIuSW>Dy1D5gSzEz>dShOk2)0bS<+A0_-ks2YQv%i<6mTb z`7lFbQz0!@N!Iz^t#n3~3k+FIN1w&!f_O|i&`c$ZSm!3rN^L5=bQ`Ul;?dp;+Qb=d z76#WiDanf!Jd;y=sF=?8Nq2xp=I(@uC<4TxTh>01LrcwHC$oNpwUmKz;44;M1;O03jb0&b4mq z;f^(OCkG@dinf^FS2|OiErCNmOzASr>P)1o?mG}JkYt)l8L=LK#jq{|U!}B#NJ9-4 z$fCBW?oLKIK{rZCq+YZ;5d>BZD%>go%8Y`tfSlF9V9g422x?8N5xG6AIkDJ?R270+ zo|2_P(5#OE&0-2|bz#)63T)7|0_pWcm2xvBEwEV(_TyMiI&-@}_NOy?6D+)RAn1-v z9e2svqwCL-jaqFch`A{wh8cbK5|Bz%P!u_CLnx+IN|wh(yXbaQ9o6IdgepqsdI#3M zbcbev4w)HC-Q=O#JK$p+{WR0p?y^7Br1h)3)Zi)&DvQ-keTY@71lH>B@SQzzXzLhp zAPYh5f8D4tS?a;WcBsu8SuU_-F;$3LE9O-D6vwuL zN4}83>jvemS?t_oXOC){?Jg6|a5)N>4$`e`TyBe@Wk!&f3Cv+~R#NXyoE$V9Wjp~L zg0p1$sfvSRDp`lU(yP*zOeqYSEJkfa7_PU%X>wV`MSBc<5vP0{B+bGg>fZ<+b-@p$*!uIU8arSAA7&B*#3I62r5mAG>_1`0d(B zQ}mKZy)W`P7KC|}zVy>La~h3q_WkOjTVdU~i8{N&B4NKL*+85}XSKg569h$EnN-ePuxiUJvq7iAOV55+3&*QrCmbP5qs-O`_z^8uh`f^?`^ z;V>%z9fGr{ElanfupB*PF{WUkEp#8983A}aVv9tfg_To_|P z5Vgvtz585gza#otJ5K4(VpPBiHg77>psUdpx$&j~6}*ylCE~dYI8M0#L;I-@HVVmF zp^4TBP4~V1`1xD6k~0rpZbu+pb#L_@(v(4jP{o->Q1*l9rD@0`Mn6q|WN)|~_6$mI z+aSptwxMnP!PfA@g00VGzvxbnhaOu1tz~;=N5HT+tv2nsarsM2iSXOyh=vrS?V?ht zsN8l#%{zwIB{gA=R8deaDMK=6tiVvhSmR#;nVsRr9dik4q(H-D=W)mHV(Yg$M>zB`F236SCa><0;A8I*Z`r6N@ z-Ldww*l~+Si=(bPc$;IALecEKdC<#8nF05o3`q_ zN=ThF_;5VVY@ePGYiYOJwWwt0q(l(Butc0ULuh)lJiQ;!JwxTVc@K$nFFc`Uk{=sP z?mpdb_xp=Z=KBN25j@Fu9{S6PUHZN~Herc7b2unQN*HnIJSdu#U{x2!PB>o5%$Cv? z5N1sg)p)2Js8bNgV0dqY*DPOGAyvZJFWs<@zYxxT8FZT&e{|98cdC9EjvO{M{bBbW z^TlMBbrMU1N&X3k;O9=NQfsR-B9w-@kjNo;V9-f%$??Qlc0EkiW8yxFX_Od4Y43mf zIEvqo;-5$HuPsyCp?PH|v_u;OYj^{Jef#X$TEB35ZY$wx&r zOFS%z4`i7@nYK0;%z@0>tguk4 zen!8rfIS}~GL`E%1zx3riJ3~b-m+vjYpif9WQcjd6~o{_Mm7fH^>C5uT&<7bg0zav zb+KCNrF@mTrA#Ge*{fK!%gO>ci^1qKlm-1x?3WPqmP!ld3$LO;8!J-Q9&zjR?)C!f zeupUmEB6XZ#JVZ?I4h-$lca{CuB^|6yj}n-f2knzht`mnyhxxD6{5yGK*zAopK;M~ z=6e+!E`tzAE&dogqCKhCH>Vend6X8|ns7wlVbeYU>O(+@32?pC;7t#(5R}q{WB}@s zg=oYV^z`Lilc0E$>C}ou;R1|sdxYetesk1I3|=l z=;(3lG*T~ewd^x0oRTtuD@BxNt!6y$+E<|DL$Px>MC5Qa-g7?xe83^5=LJgwWjN}mXb{p-Wfid}S`Wacf$-yQ2T}hp2dLnvkhB&HCL2nwqKw7 zbkTc~psI4I)vqTm~$OXp;|WjZC=)h{a)_$&qm z{Q-pt!+IqUjfRBX{lE%cH8a@sD|!uo@TB@DJsunur~XwG9G9j_bk`u_C7>u&dksvq9 zSgf%{<_a0_@>Gh*vq?8(P@uOD668V~aPmR8vG3}o3IdfP^LjkA642OU%oJ@SkDU4d z=g|iLb+-M2LPSVC8d1&{Gfp|mgCS%U4Odp2bc@tmq5S)&@2WB4qm;8O<*#s4ovSqM zGi$~gRT?~_6lE++tQK`F2QzZ=9fGrFA`W6MvYXT|yIODLC$?95QLsX?m%!i|k9D?XNRY_=Ko0w_@-9&P-;zc#Q>i4>0 zR7jlV0%I0Svw^Jm^TY(7ORAP&M1NpzO82r1?*}c^Qk6x)T|l^ZqSkRbq%1mSvp29= zOx2RgQ%s1L1ELeQRleK1nr>w(JE*6Uk;3fhbtA)TBW8^DnY(`<4geog8fYsx=n{pw z$ge8Hx{Y~-4YFL|%VM)8>Z~}RvsmKBTG{^1Iw{x(Q%mY_9LCCO1ek=9fb!livDf8^ z?n`awn&kpX7Ms;oQ$|dnnM$5T#9S{QZ?9LHukLp!P`{LbSCg>MxFLz>gUpiJmmA#m zty;OW7=n;jEPC0?sI@NAj94UbthznmQB9dG8O;j|RVu$8#8Odh2SSjsFNQyUt8}9Y z90YNSb`r@p1gVxci#{@LEmPT;2MjT+MO%|c**3t-1ghb8GnHmTEwB3UA>|BhGzoYD zkYDTYJ`?392%R>q`jb8DDF>e=C=Q)Gd?E#PYRp_a9K6a4-m5fF+p}55Q{c#A%mubu zQk5~XhPZ%shO#(P8aLP5!&7Y{NSVNpA}VPpS(!}K>e9qiW&~TAkX9*r!x@Uyd)ws! zPs~3{{AmyGIuHO1K}cesfR&papvwf7C0p5)?VYrEuJOB_6ud4P=K27ShxNe5F!S-l zcc=I5ad3iViI_xID3|2|PZom}?Mo)lyuZ%fKe>h@0c9qgTlILD35dJ)t$5=_NO*cb zBK2%{+#hUL!F0^u@2kvVSx(9s!BU{N#d6!~e`DW7StmIHO2_t<=9d{MpiEHph_wKe zMT4VEP*%|Cq9lWwNcC8Mh^dr(*@};Hh(i=5StFsk@j(enEy@H~%GPu%NbI$MBPJ+I zSk&0|jV@ODrR}H+tkrhS#Zj4&^eZ5?d2uvZ0W5}fX}30KL4_~n=|Xa9)9i&nD-I!0 zR#fd7^K9VBqbd+tGzzL^U_(%sH|3HFw_eM!a}*Jolu3bEO#9O+Gm~(E&SE;)P3Q@U zRVJ1ha3hITCR7_rET}}v<*Q@Yf+&rm04)>fP4VBuM4Y9|6jAAqIp?N|}WP6AUgTZRLD61lfT3OQf59yKGjc#gp4Iiz|Wc zvS~$)c`lNib)9xvP4c@5L+Lkv(`J|=fbQvw3XXBQYR|$J+YOEwo(Jh(_7pf50!mC| z>jDfClW0+Z@*#z?Mr_H|2uilV97bee4oR_->B{W7&+rCs$Hnt%jR~IKr5?KF@&3!# z=TBbTW1VPtb9FI%`Hp$}GT7e<`OtG?e94Wp2*dFQYZV9lXdG%oCCf%Fb13Z%YlVyD zDX_1vt}oV}F;-b1L-lo@w>Z%e2{0D`#_vQ>?sfasr>`Gt4aR(49V&4+Pk_mdZna8` zh$%FNGYLh!>MYRvSIQM;)jXhxVXeBwgkj>Qn}N+@iSd`)Bj)Z_6#^(V$q-4s=IFKd zt1pglE&zx6Q7p?x4zH8*pq6;V&TGn~x zpcGhlB;`kGqN%s#dFxNz%kke-^D7s{YKIbKMsSx2NqC*Wqw+a}HvfMUY zrSAdrAzc8>*?UrBYx~q%^lzOUOzJl&+fG(~iFwmMm}JEgzu_VXxHkz7lz*E%+G z++bT<*RJ->&#i2pdEvFV8 zE99=WxqCx6CJxDB7>!)+3MvDt)TYj% z<0^Cxpl+YxhO{`c`4v#t@09B~AOjER{f2W!MSM=M`A~*!1~~i(D1UzqOjsH?`OE|y zUmv}?SqHkSG^H*UwiM1+P()_u<~Q3Qp+rVe!=vLQ7$?DtYY1u3EVSTZkgrJDmd}@WTENjKdV63j5rJ@ zOC9C;vx?5A8H25KvTG#M|BJ%wtmVr7)0xXRi5a;<^OWh&YInYROctDH_`O2Iz8Kxv zi@0(r;(EGe>2WJQv|>TjPM){vgn z;g#1IK$-K~KaEoEYT%%vAh1hQUCKX0WN}eYB9;^tR28k?NsP|FD{D;LsDL$wop(@c ze>`0lct)kOV?@tuZDle8M^I!jy2Dl*)_PbjBLw#kCGGNGR3%__4g4{zbe;7fI@Eq{ zpjJ6NTaoqf|Z37^QKIjwul<(owpMoKcdqBTl#UI!c-hfKIy!Meg@o@to?#jz zb|z5O>7>Nu0cf!grB>I5c8SE*5gab?J18Qhz!Jm1gDCp90#OYA7NU2IzXXYVe+NP8 zB(S8&@1Tmz0j3!K9Yn%-;E+!OA2Am1dxSm3+id;(cvMgZ zL^)Y36*Hd+0!6_Tg0mX`-eGYHkbYU-Y=_{Z+kW3znJk@nex*>#%C37h`1J5<*h*vd zIvkMt8hR68;l#*SDU7R1+$)jNA zi*fz!VfpQ$c6Tc2a`lO-JgU9+MXRJWm0_ggi4~6fIp~z58!rrq8*M)e5p>?Q2@IRq5y0RYkd_`rjjsW z_&KW52N@V1?0wvJ*>IlXy8YH;eisFHURfV{lgesMYc_=uB zwJ=KuE4g*)_K+G@NNX$uS=7@ZD3a#lDGA^Zm1$tIr6_9TXzDRI&8*D(78PVP`~C+u zi)jn2;hZzPTOvVnov661?E!7bAYDVU1f_#}%Cf=^Ie^N0ZYdwtD*NS^o0& zyH^D5k)($N2&%~z^3$yLO#pE8Vn<5YuagJte!&g68{C+E<2pcfzPWxg#Y~;6Z zAV?8_?F|CiC-#XB&%_Uk(;^Evi@m7BRwSuTVg??^o^DI;(BvuU(6Yi(#Rgh%_y;I- zL#^#`qB=TZd8~q$9BbEIhb$Y&@~GmnMp04%0G%SU=sK-d5ImFm2E}PD^?~=Z`B#P* zNN@ZC))_ZiN}UPVMp_iG_;m$lVfVs21u7fX`mx9e$`VprYf+zC$ZV4Bz+KfwiLlUqM2UURj@JB6qQc}EmIpn5=65P4X%KXBp78Tep8@8fHE zR6!p;O=&~B=l_+y;!zD@A^D)0mj~3CNF&NK9%S6Z*DU-$$l1NXWqlfUq~zb+!zjJSY@zj_Jr5(~@9X<)|E)klu~UTR{{>yqnH zXVGQ((5$hI^xj@}>RTiP70!|@m%IL;w-Dqz3!-cY)hrVfhefrVFkr}|%)kB}nM#Kz z5_@PzZxlX*Ej=WQP+N`U@9|$txQN5MfctA#8q{T6SG|4%3?YWt!)`yAhRuy zKBN<A&X)k30ON!8RKPzzV zzFqC`Vc%Vc)a#_q&-m{Z~0Sf}Z6C82V0vFJ= z=%cTcwKV28rNMwcYy&nqj0*Tb;@-8b4er|rgll9S8Y5Qz zb9Ai?s)To3<$!mb{;PO%0tK9T+OOh^^+~-E&`$jH+t}Sjx+}~s`B$-yZXgA$qvT)3 z>Y5v_@CBr0>hI%pw~Cat5=yy7l*a2UzDh$j)G(#|DlSK`>|R^O`5|>K&f{i#cx$k3 zkWFd2CW}tXd$fIQ_eY#QUT{4wE4-MTH-WXJM zJa@~yjJ|*=e|vsMGql=u3q19^Jd&j<@#NVcY#wFBM!Bd<4~I1FgbB|!UarDP3$jG# z-EI9CkPseBJN%T1vQh+E2akl#B2OPY)r;CH2#9wPtmyl_c&*2MCW;Vs%y!tG{lORe z@x`ISM?5_yj&9_mf{V2(=4gS-qg2*52>m_(DoBmEEfkl~se$yu3{BRQ4;F`J!Z(XZ zw3cQkxJVKADj*7OR%UGQZ%Z-1P-gBV#kP*PDgMkb zSpm2h7P-!ZEN2(M%LGS%Ly*pAE5VRWUR;or9bH{VCDw7g{|KlL$r$we5U;c0u2zqk zVt4K@Pa8H?cpI;2O7d)=&7-=h)sev_&%L-(VS<ule^j zFjnG4!V1vRqJ<32bO>64yQ3i6j4%RSh7CrcYq zz4+FOW1#!H@82D7w7g#_8j*W6ZP?OclEN`9#><#&$*Skvvk=+Kp+L(@9UirGUY!+| z*O^XY@2Cgustgyevfk=Le4oilDOwO`xHI(a#XSRl!0bs-w{RC5-PiL)&U##tckuEr zy_YE>h((CJ0H~2iA-la1%b8i=vk?JF?LGECWVif}fxW(W&tGBG5p4h*rBI?hJ0)6! zAVp}c%{HmWfK3rC_rW^Y(flj93E@LBa_xaJ!8o9pNL7uGHKT6_$IPGzL7Cs|Suy8j z1wDT6q7c$K7QZhRyL=HCMv=Dds{lNK?ART)GpQ(=RSwVJros zMh=|0-rq=AIES0+V6Ot6X9G(fRmxZ^&h-66dc{_s;Nu;I(?T!6`{1nZ^f2<#{1)4A zu5qMaXq^u!l%*%mdJ@PiHj828Kt=uoGz5X0;q0m%4xhBV!zZeFZ~8X;!R5)VTn%>t z3i0>MIr5XA4(GKSZupbkw-rW!(Qu#(A{UU_$_9<4NVk|O1!7sxK)B&uKNSd)6akSf zJLN?HokxMUtt_%8Dk)^S(gs6AdmSm3LEwwH9uK(bk=4>+tx!Q=T_%sn*JI8(S6r6? zjbY|zdmAxY?SUVqC>8Z&an$5bG4`i7K;KVcs<-(L@Z_jxj z+1ro!P}&ROJ(#o;O`shpidMXz7^0Pa9_6G)qZD@%U*-CB;?=7|@-R7gD>_s!{Y&l8Q^rQ2Vv#j0&-fe3V_psk%5`sqd%IU<4ioK8vZt z5Z&N%oVDO7BcwTfOj*x6)n4E2Yf`*YQO!>Q&dy(`V$DZb_q@qLwSH%Dz^IaGfgVqOA65vM}-Ve?3J0gh3M4ok~$W}CbMhoElVv>U|QL2W{0 zy*Q~A!fK0o!=5+TJrl~*q^nq^t>?{2c9GQ3hiKn}d-9_K&KW$K zQ9A?J6wxWz8un5YTpes-@+kGT2Ysq)S#LehHbz~lYFTd)7Oi?Sxvej|oz|N%iDBun zN74n+jb9SmS9;;}rf0eGfiL8eb$#B5{6M)eOi8v!+l;Az&0>fEA_UaSU2mUI(1?`c zL$g{p;%lHsDY`^i0v!gtC+ypR_MurqOB`GR7X})&whdHn86nM4mXuaT6kR6FqT02! zkWAbbf1)GdiI>t^D5?l59H?XBhD&QPr7(M^Kdgnsd@|Q;?T;6655T*01FyGHGp;nh z2Q@IY%r;L>FH))D@fnjIaeVCpvv@`v2RI-fnzd?V4@*&87Mlef-ZPb&hNn$sX0a&f zA2fAf`n0Lc-!@eKP}Cfa@fFP}@hUCJAC(@#U`6k`gCGQ%y=)$3ro<#1C>NMD8ZxGl z;`~VhETrqNMWv}x5se8eElf;Hp(%oFXK$A>-WT9B5@@fzzUgW&aI%dBLX3i#n?*a9 zj;kv*PnkfHB2ep_lL-!8??j5rle`fp>M&80YovPk9rJ@YhGjH7{FtA7Oy`Jg>?mvE3ipc#X|4HP=luxl%Jlq=YI(;A&isrJ2o2b@|(ND z;=;`94$mFA{`T$bw{HFLb+Kr_e_yN?%a6-H*4@LmkKfzR_kVm`wu^54dHL||>*Ld* zXTN=S^cW+SP$a@5Z<3wf@7U=681DMhQ}8rHvy;ymd-*9%Jz_aviD8K6Ut`qkcCK|A zj9KQkD?^|sQq8dE-e%J-mz-~&8;@pl8J^$&%4z7CRj<-wwbqahasl?O{$_zYfQ~Ne z#7g#UloqQ#O5d!4*$jpsu%BGccC-8|mFceB=efslMo55DcUog7R_?|4QD$zG-H(&{ z-Ikrq`zTqgHO44itwtGTj*uteYO3E`AdoYHD@Cm(VvI=1Bv>@?J188PK;Z(vgF@G3 z-(w)kqqESB4QuDfAtORK&Y*DrUQ%@7SmEdq3SkWp$Y)lqN8pZ^LEr+vgF=T681(x) z2$W|*px@s?5IkK89sIEP9W-%Bf+vO*k+l*A3vOAZt=D1}-E#Aw)#l#^` z|M5EJz{&Ac7VPqBOkC7MHlJK8U^4+GJU>yHaS}DU_a~s`a>R`tRD=ErJ*gw_)RZ}n zyY}o>`R=&u-zW2glF>SxIvU9#zHBd^vF_`fA*9+eN7?BzzqZ9-S+YsQ? zxqX^`5x~MpP0nPIxwMOwfngR=Tl@;A7JNc&i#R-rajFg*hatzW{wx7jv!$6H}*F|Nere+AL zG?h#be(`F)cHjQwxOv&*wG&%juCE`?h+Ays+^$i1tun)9xhO1)3744T;)O?2I9r}HLVjHx?G+1wnp;tBS z4PzcE6T>=1SW36+@<4H&IBWLu6$XJ1F}>LPpKBU`;5w0xwRhXjcocYVMJoFyYm8m{ z9hpVdk@fHdpt z-RFb_bqI@-N?Z^G5yTmgfw@dzNO|ppKT6X}%B!xc`2`qf1?xD8fnpm@-mI*XWwOe; z1Zd#>=lJ3{5&g%dt?lQ_jH#j?a$Yqled59k$XGJnsY$y7cd`=vVK~ zIQrDR@zOm<&4@1C3c1LA7cQ>%Jd3nDbBSF~&o#ll)~MN>pjzRkWQ3|-4C-ScLrE*L zSc4lJdxAT!wzzAR(;pua8Oj`hs5E8gAkumW>J+F0HwajD;VPqw)LV$=Xr%PFWKn+< zD|@LBRF1M{jzMle>84o&G7`Krf&~)uuU5-1hwy$f?LdQJRHHMRH>v%*w zAFpdx@p(27bs5(~I$6d-`zF5lq_1d1qL%kb@XRa7<(T@j|g?(*{4pEe@) zxwFg_*9VXSanM-vX_GQhuM~k{gQTs8m$;RxFH-nQ7FWn1@gZe-_b^d~|J=cn!wzg7 zRRq=~Gu?79P5;1{w!KVFQ5cL<$vQb%bsTk|penm`R!b*1156XC%oz3=TgGw$i(^1q zWV10ljHgz;a%h112eA$Z0k{I(%;%0z`yL}_C!8Ch8l zIFt-6?ACN0H9hG98-mgz{?(UtPGT=ll&4=x`pRaZ4zZWjm}j?S&9}HFQ4*LGQCO>H z6Cw{tCQ_OI{DmF49QM-gE*SN28Myk6$T%yg$4S)EmTPLgW?S?4)@1DhCfvsokNJ&E zMEI8w6)f6;2AKy>#dy2Ni@Q&fCCfhyEq6im3YGw@IvV6=(Pner?_ejyUcD-Pa`vIY z0Y2{S8O-tmH_ys&*nw58qaP&1b)!6Cw_UnLRRJpl;H5o@?W%l~{Vb->uu2bz)Z4hq z$>z>t5ovm}6@K&~%49`SMdrR+ZCf=;sXZr?`Ol|bnAL}reil7+TrjQx3qjy)Wm~b;G7E`= zQHqHXoi$aB#!&-;)Cvwi%8;#ZfMOny#W0nYOTqQ7iNydJ!!Ut8E0#|Glvr$W(Q&G^ z=}~yylueS2jy#nLb}yMXGv+hb!RicXUk27CQH>R!8%&Z^cY~tVnRo|BTnrr8-SGz)evMT z*rwmk8K+-B0WRVcZ3{;jgmiNJ2&@YMVu3ZfMzjT zYOn9^@@%9q7)B{dFKasFAY>~l3;harnoHlve-W^%j$+F2=apFocW#HfqU7^PCfXs3 zt6*E{o^e*nbFy$Ma2~W4477fQHZzV_Q?)}&KoEj6apcF~Oe0f9i*gKQtvllZJB3G9 eug_MGKORpD9R50mv-r7?DOcC2zx;ptzyAw|PDCOA delta 6089 zcmeHLdstM}7C-x(LFXVMm2rDpWo7SSbofwvZZG1dDEg@Pt-s9erEBhhRWx*+UDK6>&~b%v*MOt zNIaQje?ih)jkLO;o3%%^!5P0%lH>KO0SOp?OE)ObrO%Ft0C5E zfZnkQa(LzQ#{?CKBSUpSGVmUdmOl;H8CU=z9{qXvi3QG>TcaD=jWv<}vp^cZBghLN z{`|)wr2a!dOyyq*A=zCFjFw6z|4clPhfYMF3>4@ck{`XgfslN5SzRs7_zvXc$XV!9 z#0~?kz~LB&N52zD4iAD+;&0^-$?oVqP^Iaoql@C($PddgzMYVgt=eEzX9I~JfrOH_ z1|(-`#hBKA3Vc^!Syk2Cs6LIWK-r&&W3ygp6$YE*RlCH63yf9r;KfsyD)(35z=;6m9 zDaUEK6B0!?vm0CvIJ3@O14r71(J}nEQ)8>RB|}p`#~B)g9+`X7-Rw5r09gr6%uqx7 z4G*`tG}fLM;&&i#aA|5?8%Y|ik7%~L&F_O73yv0L*B2GT3o|u!7ET$W<8RB8G`G4L zTz_zFbZ?r$wJcGM!8xNo-BUJ>H@G!*1!RaEMpHo3ybgC*CbE>vi_)`LEpPB> zY7=g@|Y)b= z38y}NH>hjD8SYZ-z6NJx4Zf(cIDDQK&9UGp+hIHjYgh)(4$jQU>;2p^NK-EdHH^si z;SG?@L*<}-X3TZ~9IZsxP}_G2*>Bd|>~`KTSTiqyjMioBwW#^383J;U(X{fVE_~9E z9Cb1dI0^NLsP*8CbJC2x6OHOJlCSTd6?PY%O89zL7JG{~+^(q-%7w8{lJ;TG57pGi zAxVcFnKx&+*=gPYSxTJYm7Z``!Y#uzbq8cdw2@-@`#8RKSdN;GYD3d9?#*x`2N9oZmnU{hi7ln7LY#h?P+%ig&|JjXC8kM7Js91D{CGK^()m7jogF{x3 zz3;dsPh%P{%$vx3e0yF`Ciw9@&GJ#AQOA)ny=>MxY%UwN$1(26?_JZD8 zBVLtKK8X5JHuTnl9atYJ|j>1hEuItu>NoWxDi6Bzv=hazYAWWsq-;WPffb$#~G0dJm9dSOX%3c_3=7 zk>s@?!ucR-gfwm;F=(xk99^tS4Ww~Pg8UL`l<`CYQlvdc3VskZzy5n8(u$S^<*kwN zv>#%4_77$vWAj4mH#$T9H635=T%bzQ{RuvffaMr#x z$4=M&eWh*hzBB!H*G|6F?)^U})`#zOUwHW2PwSgXPn7lU_~dtN_LUv4t?QCl^2Tw0 zU_f_vxlQgT+a8ZjUYPUKrW51NZ;qSaA>qa0T5{sm#cviI{zFu!z`sts+9v+Wkw2DB zKljj}Q}b6nwP8!$0N>^prMJ(1d+yv!``v+gz1d$PbC(9DKfk}~iga~tLbj)G{@x^> zvck=~H%JFWQ4YR(N|My-@aUYHD+fo?;YzVe!X(nlZ%_ezifKtwYRF%>H}*$ z>`Vu7sh9i+lf-?!<&I%5Vdr%S++&k{4By};5uYlX!-`PD+Y1O+ku0z)Ro*6t9mTsh zGT1S8m&v9s?aHeuN2pLWl6dg4ob8kT{gcs1N)?#4H9m&)7UC(N@gVA>|IY}i zfKorT3J}TY>{4;2HU~s9s_=J%NS`V?*}}gO^eu>ngHN5LNH3uUATmOgofOT%XEH*b zlOB~wdL~(@@`vM@#*huF{-j55OVT4*=na4`e!ZXU(p!La#}B^pbs-rc2Wap%vW)gb ztt1+wm1GfXQhG#_2AL%@G%8ZOXi|FmV(~~JivukK`9b%A?guRe(d*(~P#I_js2p?` zh^kHzXbPwpGzsJYQJqZ!bp_#LPD%h#4W_Ri1WZ3-i+~hCr(fX z$PVfQx((D5L@TDxro|x273HJ^G)QcZP*QzVdg-HvqEiQ|0u_R&()|uJ9y9@TCy1)$ z7*IB700>{5dI|Rc`+@p{3P1xv8i=+~Du^;pfu@X6hQ?lh?xAObf=_8Aq|^~L(GS|u z1$su3OtftSXQGuTxt*CjMSFO;B(xNzsN)bY*eCu)D~^p|o(FTy=I-J^ijvRrMNF!a z#41F;RK>}1#hg?KCyGYmO2qk8#bOOzV(jt#{#x_ENyRdo;<4Fnh-0m|wU07``NSiA zpuSSg*4S@Hz(R&C!-lL>idAWfg)I=< zM<`uPNRctxgseA-FVJNTU4xySHfh2a*-b;P&pu8>+c5U}2#?4g3Bh1dOmd^!8oDMc zxu?f~+;$y27@rRBF+sf80zGT!hRm{mwfe;a+g^r()8-(B)1ny)@|7@g&8FnB4Pr!J ztnZ*$LJ%Xi_r)wJ;$UAyY?H9qvCz=%*qAMc=bt-famno7;AALOcBtoxbpUJV5-iej z_^)rin=u7*It-`k#K)xfp7@&`lN5-q4yfOXvlWHx&FG&q`e^mF;ZS$kU>KWPjDrFj zE@qQn=&EZ&r}kBmE0(`bX6;b)NHfJ#P;eQSWRidCEi00@KE7}n6wpw=eGQW0!I)ln1A=3wDU4boj7aWC3oXcSy{If-7`^*Qqih z-MR5{895nT4AvNlWj0=WIa%>4}mtGNZ*H=Q#E&orwHSvDb;b?hzd_0MkWL1_n2Z`NTQJz6{0b z3SH)vyNaLh+vnUGxEst$=(=y~$;Puu)qUd76ZGN^k>-M-BVw2flbjNZz{Q7d0~el1 zi2ATJtxk`KgZ`hq6f3s5lvsAZI6(Ry@gwxDq1(SlH}0753-^S=k*PR; zY0o=s{V0&}!k3Bpw}}Sm!Hti=SwokAFDDgjy7ItJJ%aY2en2oc)F%onz#6)39NqWr zO_mSd>7*}9&(CLKj2rX*`cX<2>&eh*5pXNFcXT8gi9Wg<0Y?LhHT#v^E-MVa*9!)Q zXV3HGBs#>{6s5B;A5^*rat=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { Sphinx } from "@sphinx-labs/contracts/SphinxPlugin.sol"; import { console2 } from "forge-std/src/console2.sol"; import { Script } from "forge-std/src/Script.sol"; -contract BaseScript is Script { +contract BaseScript is Script, Sphinx { using Strings for uint256; /// @dev The Avalanche chain ID. uint256 internal constant AVALANCHE_CHAIN_ID = 43_114; + /// @dev The project name for the Sphinx plugin. + string internal constant SPHINX_PROJECT_NAME = "test-test"; + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -26,24 +30,29 @@ contract BaseScript is Script { /// block gas limit. uint256 internal maxCount; - /// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined. + /// @dev Used to derive the broadcaster's address if $EOA is not defined. string internal mnemonic; + /// @dev The project name for the Sphinx plugin. + string internal sphinxProjectName; + /// @dev Initializes the transaction broadcaster like this: /// - /// - If $ETH_FROM is defined, use it. + /// - If $EOA is defined, use it. /// - Otherwise, derive the broadcaster address from $MNEMONIC. /// - If $MNEMONIC is not defined, default to a test mnemonic. + /// - If $SPHINX_PROJECT_NAME is not defined, default to a test project name. /// - /// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line. + /// The use case for $EOA is to specify the broadcaster key and its address via the command line. constructor() { - address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); + address from = vm.envOr({ name: "EOA", defaultValue: address(0) }); if (from != address(0)) { broadcaster = from; } else { mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC }); (broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 }); } + sphinxProjectName = vm.envOr({ name: "SPHINX_PROJECT_NAME", defaultValue: SPHINX_PROJECT_NAME }); // Sets `maxCount` to 300 for Avalanche, and 500 for all other chains. if (block.chainid == AVALANCHE_CHAIN_ID) { @@ -59,6 +68,19 @@ contract BaseScript is Script { vm.stopBroadcast(); } + /// @dev Configures the Sphinx plugin to use Sphinx managed deployment for smart contracts. + /// Refer to https://github.com/sphinx-labs/sphinx/tree/main/docs. + /// CLI example: + /// - bun sphinx propose script/DeployCore.s.sol --networks testnets --sig "runSphinx(address)" $ADMIN + function configureSphinx() public override { + sphinxConfig.mainnets = ["arbitrum", "avalanche", "bnb", "gnosis", "ethereum", "optimism", "polygon"]; + sphinxConfig.orgId = vm.envOr({ name: "SPHINX_ORG_ID", defaultValue: TEST_MNEMONIC }); + sphinxConfig.owners = [broadcaster]; + sphinxConfig.projectName = sphinxProjectName; + sphinxConfig.testnets = ["sepolia"]; + sphinxConfig.threshold = 1; + } + /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: /// https://github.com/Arachnid/deterministic-deployment-proxy /// diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index c7635ab7f..44d1b9641 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -15,7 +15,8 @@ import { BaseScript } from "./Base.s.sol"; /// 3. {SablierV2LockupLinear} /// 4. {SablierV2LockupTranched} contract DeployCore is BaseScript { - function run(address initialAdmin) + /// @dev Deploy using Forge CLI. + function runBroadcast(address initialAdmin) public virtual broadcast @@ -25,6 +26,33 @@ contract DeployCore is BaseScript { SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) + { + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx(address initialAdmin) + public + virtual + sphinx + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor + ) + { + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); + } + + function _run(address initialAdmin) + internal + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor + ) { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 9e400dbb7..3f52967b2 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -14,7 +14,8 @@ import { BaseScript } from "./Base.s.sol"; /// 2. {SablierV2LockupLinear} /// 3. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor ) @@ -26,6 +27,37 @@ contract DeployCore2 is BaseScript { SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) + { + (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor + ) + public + virtual + sphinx + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched + ) + { + (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor + ) + internal + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched + ) { lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index bde134d9b..22eaddabf 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -17,7 +17,8 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - function run(address initialAdmin) + /// @dev Deploy using Forge. + function runBroadcast(address initialAdmin) public virtual broadcast @@ -27,6 +28,33 @@ contract DeployDeterministicCore is BaseScript { SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) + { + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); + } + + /// @dev Deploy using Sphinx. + function runSphinx(address initialAdmin) + public + virtual + sphinx + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor + ) + { + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); + } + + function _run(address initialAdmin) + internal + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor + ) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index d86bda48e..83d78b6ca 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -16,7 +16,8 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor ) @@ -28,6 +29,37 @@ contract DeployDeterministicCore2 is BaseScript { SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) + { + (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor + ) + public + virtual + sphinx + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched + ) + { + (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor + ) + internal + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched + ) { bytes32 salt = constructCreate2Salt(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 68a85d56c..d8b2a9e65 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -9,7 +9,8 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -17,6 +18,29 @@ contract DeployDeterministicLockupDynamic is BaseScript { virtual broadcast returns (SablierV2LockupDynamic lockupDynamic) + { + lockupDynamic = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupDynamic lockupDynamic) + { + lockupDynamic = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index de36726ab..47dc07651 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -9,7 +9,8 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -17,6 +18,29 @@ contract DeployDeterministicLockupLinear is BaseScript { virtual broadcast returns (SablierV2LockupLinear lockupLinear) + { + lockupLinear = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupLinear lockupLinear) + { + lockupLinear = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupLinear lockupLinear) { bytes32 salt = constructCreate2Salt(); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor); diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index b52807539..08a3e550c 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -9,7 +9,8 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupTranched is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -17,6 +18,29 @@ contract DeployDeterministicLockupTranched is BaseScript { virtual broadcast returns (SablierV2LockupTranched lockupTranched) + { + lockupTranched = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupTranched lockupTranched) + { + lockupTranched = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index f7a72bff2..21de03352 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -8,7 +8,17 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { - function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + /// @dev Deploy using Forge CLI. + function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + nftDescriptor = _run(); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { + nftDescriptor = _run(); + } + + function _run() internal returns (SablierV2NFTDescriptor nftDescriptor) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index e99c78b2f..73ee2f387 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -7,7 +7,8 @@ import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupDynamic is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -15,6 +16,29 @@ contract DeployLockupDynamic is BaseScript { virtual broadcast returns (SablierV2LockupDynamic lockupDynamic) + { + lockupDynamic = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupDynamic lockupDynamic) + { + lockupDynamic = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupDynamic lockupDynamic) { lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxCount); } diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index 940966a2f..4690ab9a3 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -7,7 +7,8 @@ import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupLinear is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -15,6 +16,29 @@ contract DeployLockupLinear is BaseScript { virtual broadcast returns (SablierV2LockupLinear lockupLinear) + { + lockupLinear = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupLinear lockupLinear) + { + lockupLinear = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupLinear lockupLinear) { lockupLinear = new SablierV2LockupLinear(initialAdmin, initialNFTDescriptor); } diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 2dc6d8845..1c5c97878 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -7,7 +7,8 @@ import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupTranched is BaseScript { - function run( + /// @dev Deploy using Forge CLI. + function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -15,6 +16,29 @@ contract DeployLockupTranched is BaseScript { virtual broadcast returns (SablierV2LockupTranched lockupTranched) + { + lockupTranched = _run(initialAdmin, initialNFTDescriptor); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + public + virtual + sphinx + returns (SablierV2LockupTranched lockupTranched) + { + lockupTranched = _run(initialAdmin, initialNFTDescriptor); + } + + function _run( + address initialAdmin, + ISablierV2NFTDescriptor initialNFTDescriptor + ) + internal + returns (SablierV2LockupTranched lockupTranched) { lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxCount); } diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index 6f3019171..2649b5159 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.s.sol @@ -6,7 +6,17 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployNFTDescriptor is BaseScript { - function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + /// @dev Deploy using Forge CLI. + function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + nftDescriptor = _run(); + } + + /// @dev Deploy using Sphinx CLI. + function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { + nftDescriptor = _run(); + } + + function _run() internal returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = new SablierV2NFTDescriptor(); } } From 4489cab2495b9bac1604df999c091256e0eb89d7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 20 Mar 2024 23:26:27 +0000 Subject: [PATCH 071/132] perf: remove unnecessary variable (#860) --- src/SablierV2LockupTranched.sol | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index f27cb7f30..8341bf884 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -13,19 +13,19 @@ import { Lockup, LockupTranched } from "./types/DataTypes.sol"; /* -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ - -██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ████████╗██████╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗███████╗██████╗ +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ + +██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ████████╗██████╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗███████╗██████╗ ██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ ╚══██╔══╝██╔══██╗██╔══██╗████╗ ██║██╔════╝██║ ██║██╔════╝██╔══██╗ ██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ ██║ ██████╔╝███████║██╔██╗ ██║██║ ███████║█████╗ ██║ ██║ ██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ ██║ ██╔══██╗██╔══██║██║╚██╗██║██║ ██╔══██║██╔══╝ ██║ ██║ ███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ ██║ ██║ ██║██║ ██║██║ ╚████║╚██████╗██║ ██║███████╗██████╔╝ -╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═════╝ +╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═════╝ */ @@ -200,13 +200,12 @@ contract SablierV2LockupTranched is // Using unchecked arithmetic is safe because the sum of the tranche amounts is equal to the total amount // at this point. uint128 streamedAmount = tranches[0].amount; - uint40 currentTrancheTimestamp = tranches[1].timestamp; + uint256 index = 1; unchecked { - while (currentTrancheTimestamp <= currentTime) { + while (tranches[index].timestamp <= currentTime) { streamedAmount += tranches[index].amount; index += 1; - currentTrancheTimestamp = tranches[index].timestamp; } } From 6775fec1070dc6625db7d4ae59f399d194fb1aa8 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 21 Mar 2024 15:42:45 +0200 Subject: [PATCH 072/132] build: add base chain in foundry endpoints --- foundry.toml | 1 + script/Base.s.sol | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/foundry.toml b/foundry.toml index 4f6d33a7c..237a2d1a3 100644 --- a/foundry.toml +++ b/foundry.toml @@ -99,6 +99,7 @@ [rpc_endpoints] arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}" avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}" + base = "https://mainnet.base.org" bnb = "https://bsc-dataseed.binance.org" gnosis = "https://rpc.gnosischain.com" localhost = "http://localhost:8545" diff --git a/script/Base.s.sol b/script/Base.s.sol index 12ee9e79b..4e0c6a931 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -73,7 +73,7 @@ contract BaseScript is Script, Sphinx { /// CLI example: /// - bun sphinx propose script/DeployCore.s.sol --networks testnets --sig "runSphinx(address)" $ADMIN function configureSphinx() public override { - sphinxConfig.mainnets = ["arbitrum", "avalanche", "bnb", "gnosis", "ethereum", "optimism", "polygon"]; + sphinxConfig.mainnets = ["arbitrum", "avalanche", "base", "bnb", "gnosis", "ethereum", "optimism", "polygon"]; sphinxConfig.orgId = vm.envOr({ name: "SPHINX_ORG_ID", defaultValue: TEST_MNEMONIC }); sphinxConfig.owners = [broadcaster]; sphinxConfig.projectName = sphinxProjectName; From a86edeeecb57a2ba2e6fb5a4a4049e62f0b8f2a6 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:18:56 +0200 Subject: [PATCH 073/132] refactor: keep streamedAmountOf only in SablierV2Lockup (#864) docs: move dev natspec in _calculateStreamedAmount function chore: update Precompiles --- precompiles/Precompiles.sol | 6 +++--- src/SablierV2LockupDynamic.sol | 22 +++++++++++--------- src/SablierV2LockupLinear.sol | 20 ++++++++++-------- src/SablierV2LockupTranched.sol | 21 ++++++++----------- src/abstracts/SablierV2Lockup.sol | 1 - src/interfaces/ISablierV2Lockup.sol | 6 ++++++ src/interfaces/ISablierV2LockupDynamic.sol | 23 --------------------- src/interfaces/ISablierV2LockupLinear.sol | 22 -------------------- src/interfaces/ISablierV2LockupTranched.sol | 20 ------------------ 9 files changed, 41 insertions(+), 100 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 211c84b50..305f44aa7 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -25,11 +25,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f1962005a3b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156399081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab826141c7565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141c7565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b657610713846141c7565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614605565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161465f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d8588614605565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614197565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a6141c7565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be916141ef565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b87825285522001541694613151818988614605565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e6134378361465f565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b916141ef565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c88614605565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a8906142db565b90565b6137a89061420a565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b0360408401511660206101008501510151906144bb565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b038351169030903390614594565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b036101008601515116903390614594565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b515116906141ef565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b3d156141c2573d906141a8826129b2565b916141b66040519384612990565b82523d6000602084013e565b606090565b6137a8906141d48161465f565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff61423f600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146da565b91808252600a602052604082208054156142c75790829167ffffffffffffffff9352614299602083205482845260096020526142946001600160801b03968760026040882001541696879360801c16906147ca565b614838565b9283136142af5750506142ab90614922565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161430183612973565b80549661012061438760026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a60205261439e858520612df7565b91849680876143ac866139f8565b5101511692828288955b161061448557509161443a6142949284888161443f98976001600160801b039e8f6143e1898c613a05565b5151169d8e9a67ffffffffffffffff60206143fc8c84613a05565b5101511699848361440d8385613a05565b5101511696508015614479576144299293506000190190613a05565b5101511680925b03169203166146da565b6147ca565b9283136144585750506144528391614922565b16011690565b5160200151929392831692841683101591506144749050575090565b905090565b50505051168092614430565b8093986001600160801b03908161449c8c89613a05565b51511601169801928282808a6144b2888a613a05565b510151166143b6565b919091604051906144cb82612943565b600091828152826020820152936001600160801b03928383169182156145755767016345785d8a000080821161453e57506145078591846154ea565b166020870192818452111561452a5750908261452592511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061458982612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb576146039260405261495e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146039161465a606483612990565b61495e565b8060005260096020526146786002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146146ab57506001600160801b039150602001511690565b5460f81c6146bd57506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b600160ff1b8082149081156147c0575b5061479657600081121561478d57614713816000035b60008412156147865783600003906149fa565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474f57600019911813156147495790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fa565b61471381614700565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ea565b806147e557506147e057670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483257508061480a575050670de0b6b3a764000090565b670de0b6b3a7640000811461482e57614829906142946137a893614af4565b614c36565b5090565b91505090565b600160ff1b808214908115614918575b506148ee5760008112156148e557614871816000035b60008412156148de5783600003906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a757600019911813156147495790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ea565b6148718161485e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614848565b6000811261492d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614989600080836020829551910182875af1614982614197565b9084615599565b9081519182151592836149d2575b5050506149a15750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614997565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab65782851015614a7a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac4570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac4576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0557670de0b6b3a764000092838112614be257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd657506706f05b59d3b20000905b848213614baa5750505050500290565b808391020590671bc16d674ec80000821215614bc9575b831d90614b9a565b8091950194831d90614bc1565b93505093925050020290565b6000199392508015614ac4576ec097ce7bc90715b34b9f10000000000591614b15565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c655768033dd1780914b9711419811261384a57614c5c90600003614c36565b6137a890614ada565b680a688906bd8affffff81136154b957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539c575b66ff0000000000008316615294575b65ff00000000008316615194575b64ff00000000831661509c575b63ff0000008316614fac575b62ff00008316614ec4575b61ff008316614de4575b60ff8316614d0d575b02911c60bf031c90565b60808316614dd2575b838316614dc0575b60208316614dae575b60108316614d9c575b60088316614d8a575b60048316614d78575b60028316614d66575b6001831615614d03576801000000000000000102831c614d03565b6801000000000000000102831c614d4b565b6801000000000000000302831c614d42565b6801000000000000000602831c614d39565b6801000000000000000b02831c614d30565b6801000000000000001602831c614d27565b6801000000000000002c02831c614d1e565b6801000000000000005902831c614d16565b6180008316614eb2575b6140008316614ea0575b6120008316614e8e575b6110008316614e7c575b6108008316614e6a575b6104008316614e58575b6102008316614e46575b610100831615614cfa57680100000000000000b102831c614cfa565b6801000000000000016302831c614e2a565b680100000000000002c602831c614e20565b6801000000000000058c02831c614e16565b68010000000000000b1702831c614e0c565b6801000000000000162e02831c614e02565b68010000000000002c5d02831c614df8565b680100000000000058b902831c614dee565b628000008316614f9a575b624000008316614f88575b622000008316614f76575b621000008316614f64575b620800008316614f52575b620400008316614f40575b620200008316614f2e575b62010000831615614cf0576801000000000000b17202831c614cf0565b680100000000000162e402831c614f11565b6801000000000002c5c802831c614f06565b68010000000000058b9102831c614efb565b680100000000000b172102831c614ef0565b68010000000000162e4302831c614ee5565b680100000000002c5c8602831c614eda565b6801000000000058b90c02831c614ecf565b6380000000831661508a575b63400000008316615078575b63200000008316615066575b63100000008316615054575b63080000008316615042575b63040000008316615030575b6302000000831661501e575b6301000000831615614ce55768010000000000b1721802831c614ce5565b6801000000000162e43002831c615000565b68010000000002c5c86002831c614ff4565b680100000000058b90c002831c614fe8565b6801000000000b17217f02831c614fdc565b680100000000162e42ff02831c614fd0565b6801000000002c5c85fe02831c614fc4565b68010000000058b90bfc02831c614fb8565b6480000000008316615182575b6440000000008316615170575b642000000000831661515e575b641000000000831661514c575b640800000000831661513a575b6404000000008316615128575b6402000000008316615116575b640100000000831615614cd957680100000000b17217f802831c614cd9565b68010000000162e42ff102831c6150f7565b680100000002c5c85fe302831c6150ea565b6801000000058b90bfce02831c6150dd565b68010000000b17217fbb02831c6150d0565b6801000000162e42fff002831c6150c3565b68010000002c5c8601cc02831c6150b6565b680100000058b90c0b4902831c6150a9565b658000000000008316615282575b654000000000008316615270575b65200000000000831661525e575b65100000000000831661524c575b65080000000000831661523a575b650400000000008316615228575b650200000000008316615216575b65010000000000831615614ccc576801000000b17218355102831c614ccc565b680100000162e430e5a202831c6151f6565b6801000002c5c863b73f02831c6151e8565b68010000058b90cf1e6e02831c6151da565b680100000b1721bcfc9a02831c6151cc565b68010000162e43f4f83102831c6151be565b680100002c5c89d5ec6d02831c6151b0565b6801000058b91b5bc9ae02831c6151a2565b6680000000000000831661538a575b66400000000000008316615378575b66200000000000008316615366575b66100000000000008316615354575b66080000000000008316615342575b66040000000000008316615330575b6602000000000000831661531e575b6601000000000000831615614cbe5768010000b17255775c0402831c614cbe565b6801000162e525ee054702831c6152fd565b68010002c5cc37da949202831c6152ee565b680100058ba01fb9f96d02831c6152df565b6801000b175effdc76ba02831c6152d0565b680100162f3904051fa102831c6152c1565b6801002c605e2e8cec5002831c6152b2565b68010058c86da1c09ea202831c6152a3565b678000000000000000831661549a575b6740000000000000008316615488575b6720000000000000008316615476575b6710000000000000008316615464575b6708000000000000008316615452575b6704000000000000008316615440575b670200000000000000831661542e575b670100000000000000831615614caf57680100b1afa5abcbed6102831c614caf565b68010163da9fb33356d802831c61540c565b680102c9a3e778060ee702831c6153fc565b6801059b0d31585743ae02831c6153ec565b68010b5586cf9890f62a02831c6153dc565b6801172b83c7d517adce02831c6153cc565b6801306fe0a31b7152df02831c6153bc565b5077b504f333f9de6484800000000000000000000000000000006153ac565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558857670de0b6b3a7640000908183101561555157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d857508051156155ae57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615623575b6155e9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e156fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962005a3b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156399081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab82614242565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614242565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614242565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614680565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614197565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d8588614680565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614212565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a614242565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be9161426a565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b87825285522001541694613151818988614680565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e61343783614197565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b9161426a565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c88614680565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a890614356565b90565b6137a890614285565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b036040840151166020610100850151015190614536565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b03835116903090339061460f565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b03610100860151511690339061460f565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b5151169061426a565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b8060005260096020526141b06002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146141e357506001600160801b039150602001511690565b5460f81c6141f557506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b3d1561423d573d90614223826129b2565b916142316040519384612990565b82523d6000602084013e565b606090565b6137a89061424f81614197565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff6142ba600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146da565b91808252600a602052604082208054156143425790829167ffffffffffffffff93526143146020832054828452600960205261430f6001600160801b03968760026040882001541696879360801c16906147ca565b614838565b92831361432a57505061432690614922565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161437c83612973565b80549661012061440260026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a602052614419858520612df7565b9184968087614427866139f8565b5101511692828288955b16106145005750916144b561430f928488816144ba98976001600160801b039e8f61445c898c613a05565b5151169d8e9a67ffffffffffffffff60206144778c84613a05565b510151169984836144888385613a05565b51015116965080156144f4576144a49293506000190190613a05565b5101511680925b03169203166146da565b6147ca565b9283136144d35750506144cd8391614922565b16011690565b5160200151929392831692841683101591506144ef9050575090565b905090565b505050511680926144ab565b8093986001600160801b0390816145178c89613a05565b51511601169801928282808a61452d888a613a05565b51015116614431565b9190916040519061454682612943565b600091828152826020820152936001600160801b03928383169182156145f05767016345785d8a00008082116145b957506145828591846154ea565b16602087019281845211156145a5575090826145a092511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061460482612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761467e9260405261495e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261467e916146d5606483612990565b61495e565b600160ff1b8082149081156147c0575b5061479657600081121561478d57614713816000035b60008412156147865783600003906149fa565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474f57600019911813156147495790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fa565b61471381614700565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ea565b806147e557506147e057670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483257508061480a575050670de0b6b3a764000090565b670de0b6b3a7640000811461482e576148299061430f6137a893614af4565b614c36565b5090565b91505090565b600160ff1b808214908115614918575b506148ee5760008112156148e557614871816000035b60008412156148de5783600003906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a757600019911813156147495790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ea565b6148718161485e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614848565b6000811261492d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614989600080836020829551910182875af1614982614212565b9084615599565b9081519182151592836149d2575b5050506149a15750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614997565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab65782851015614a7a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac4570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac4576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0557670de0b6b3a764000092838112614be257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd657506706f05b59d3b20000905b848213614baa5750505050500290565b808391020590671bc16d674ec80000821215614bc9575b831d90614b9a565b8091950194831d90614bc1565b93505093925050020290565b6000199392508015614ac4576ec097ce7bc90715b34b9f10000000000591614b15565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c655768033dd1780914b9711419811261384a57614c5c90600003614c36565b6137a890614ada565b680a688906bd8affffff81136154b957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539c575b66ff0000000000008316615294575b65ff00000000008316615194575b64ff00000000831661509c575b63ff0000008316614fac575b62ff00008316614ec4575b61ff008316614de4575b60ff8316614d0d575b02911c60bf031c90565b60808316614dd2575b838316614dc0575b60208316614dae575b60108316614d9c575b60088316614d8a575b60048316614d78575b60028316614d66575b6001831615614d03576801000000000000000102831c614d03565b6801000000000000000102831c614d4b565b6801000000000000000302831c614d42565b6801000000000000000602831c614d39565b6801000000000000000b02831c614d30565b6801000000000000001602831c614d27565b6801000000000000002c02831c614d1e565b6801000000000000005902831c614d16565b6180008316614eb2575b6140008316614ea0575b6120008316614e8e575b6110008316614e7c575b6108008316614e6a575b6104008316614e58575b6102008316614e46575b610100831615614cfa57680100000000000000b102831c614cfa565b6801000000000000016302831c614e2a565b680100000000000002c602831c614e20565b6801000000000000058c02831c614e16565b68010000000000000b1702831c614e0c565b6801000000000000162e02831c614e02565b68010000000000002c5d02831c614df8565b680100000000000058b902831c614dee565b628000008316614f9a575b624000008316614f88575b622000008316614f76575b621000008316614f64575b620800008316614f52575b620400008316614f40575b620200008316614f2e575b62010000831615614cf0576801000000000000b17202831c614cf0565b680100000000000162e402831c614f11565b6801000000000002c5c802831c614f06565b68010000000000058b9102831c614efb565b680100000000000b172102831c614ef0565b68010000000000162e4302831c614ee5565b680100000000002c5c8602831c614eda565b6801000000000058b90c02831c614ecf565b6380000000831661508a575b63400000008316615078575b63200000008316615066575b63100000008316615054575b63080000008316615042575b63040000008316615030575b6302000000831661501e575b6301000000831615614ce55768010000000000b1721802831c614ce5565b6801000000000162e43002831c615000565b68010000000002c5c86002831c614ff4565b680100000000058b90c002831c614fe8565b6801000000000b17217f02831c614fdc565b680100000000162e42ff02831c614fd0565b6801000000002c5c85fe02831c614fc4565b68010000000058b90bfc02831c614fb8565b6480000000008316615182575b6440000000008316615170575b642000000000831661515e575b641000000000831661514c575b640800000000831661513a575b6404000000008316615128575b6402000000008316615116575b640100000000831615614cd957680100000000b17217f802831c614cd9565b68010000000162e42ff102831c6150f7565b680100000002c5c85fe302831c6150ea565b6801000000058b90bfce02831c6150dd565b68010000000b17217fbb02831c6150d0565b6801000000162e42fff002831c6150c3565b68010000002c5c8601cc02831c6150b6565b680100000058b90c0b4902831c6150a9565b658000000000008316615282575b654000000000008316615270575b65200000000000831661525e575b65100000000000831661524c575b65080000000000831661523a575b650400000000008316615228575b650200000000008316615216575b65010000000000831615614ccc576801000000b17218355102831c614ccc565b680100000162e430e5a202831c6151f6565b6801000002c5c863b73f02831c6151e8565b68010000058b90cf1e6e02831c6151da565b680100000b1721bcfc9a02831c6151cc565b68010000162e43f4f83102831c6151be565b680100002c5c89d5ec6d02831c6151b0565b6801000058b91b5bc9ae02831c6151a2565b6680000000000000831661538a575b66400000000000008316615378575b66200000000000008316615366575b66100000000000008316615354575b66080000000000008316615342575b66040000000000008316615330575b6602000000000000831661531e575b6601000000000000831615614cbe5768010000b17255775c0402831c614cbe565b6801000162e525ee054702831c6152fd565b68010002c5cc37da949202831c6152ee565b680100058ba01fb9f96d02831c6152df565b6801000b175effdc76ba02831c6152d0565b680100162f3904051fa102831c6152c1565b6801002c605e2e8cec5002831c6152b2565b68010058c86da1c09ea202831c6152a3565b678000000000000000831661549a575b6740000000000000008316615488575b6720000000000000008316615476575b6710000000000000008316615464575b6708000000000000008316615452575b6704000000000000008316615440575b670200000000000000831661542e575b670100000000000000831615614caf57680100b1afa5abcbed6102831c614caf565b68010163da9fb33356d802831c61540c565b680102c9a3e778060ee702831c6153fc565b6801059b0d31585743ae02831c6153ec565b68010b5586cf9890f62a02831c6153dc565b6801172b83c7d517adce02831c6153cc565b6801306fe0a31b7152df02831c6153bc565b5077b504f333f9de6484800000000000000000000000000000006153ac565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558857670de0b6b3a7640000908183101561555157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d857508051156155ae57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615623575b6155e9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e156fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f6200499e3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c19081620003dd8239608051816139430152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5a57508063027b674414612f3757806306fdde0314612e72578063081812fc14612e53578063095ea7b314612d5a5780631400ecec14612cba5780631c1cdd4c14612c555780631e99d56914612c3757806323b872dd14612c1f57806340e58ee5146129a1578063425d30dd1461295057806342842e0e1461290057806342966c681461272557806344267570146126fe5780634857501f146126885780634869e12d1461264d5780634cc55e11146121bd57806353b157271461209e5780636352211e1461206e5780636d0cee751461206e57806370a0823114611ffe57806375829def14611f6b578063780a82c814611f1e5780637cad6cd114611e245780637de6b1db14611bfd5780638659c270146118ac578063894e9a0d1461158c5780638f69b993146114f05780639067b677146114a057806395d89b4114611391578063a22cb465146112d4578063a80fc07114611282578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613089565b916102786131e6565b92610281613939565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a757610303896140ac565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134dd565b906103b181868401511692826040818351169201511690613220565b161115610532575b848c528252600160408c20015416946103d3818a886140d7565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613105565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613105565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613995565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613089565b91610278816140ac565b503461064c57604036600319011261064c5761076b613073565b6040610775613089565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916140ac565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134be565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613136565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613692565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061304e565b0390f35b909192503d8082843e6109fd81846131a8565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131ca565b93610a4160405195866131a8565b83855285848401011161064c575090610a5f9184808501910161302b565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613089565b610a9c613939565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae3866140ac565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f4565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613939565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a6140ac565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613220565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb68186886140d7565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c90613105565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e0090613105565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613995565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613073565b61101a613089565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131ca565b9361105760405195866131a8565b8585523660248783010111610a67578561108296602460209301838801378501015260443591613525565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061376d565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613939565b61115b6134be565b9064ffffffffff80421680845281611171613511565b1661126c575b60e4359082821682036112675701166040830152600435916001600160a01b0391828416809403611267576024359083821680920361126757604435906001600160801b038216809203611267576064359085821680920361064c5750608435918215158093036112675760a4359384151580950361126757604051976111fd89613119565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126757604051916112378361318c565b610104359182168203611267578261125f9260209452610124358482015260e08201526139fe565b604051908152f35b600080fd5b81611275613511565b8201166020850152611177565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112ee613073565b60243590811515809203611267576001600160a01b03169081156113605733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c9260018516948515611496575b602095868610811461148257858852879493929187908215611460575050600114611406575b50506113f2925003836131a8565b6109e660405192828493845283019061304e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106114485750506113f2935082010138806113e4565b80548389018501528794508693909201918101611430565b92509350506113f294915060ff191682840152151560051b82010138806113e4565b602483634e487b7160e01b81526022600452fd5b93607f16936113be565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576115299061376d565b906005821015908161156a576002831491821561157e575b8215611555575b6020836040519015158152f35b90915061156a57506004602091143880611548565b80634e487b7160e01b602492526021600452fd5b506003831491506000611541565b503461064c57602036600319011261064c57806101606040516115ae81613152565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f16134be565b61014082015201526004358152600960205260ff600160408320015460a81c1615611894576004358152600960205260408120906116bf6002604051936116378561316f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134dd565b6101208301526116d060043561376d565b6005811015611880576101606101c093600264ffffffffff9314611875575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b61177c8d613152565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116ef565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118df9036906004016130d4565b91906118e9613939565b83925b8084106118f7578480f35b611902848284613498565b359361190c613939565b848652600980855260ff90600190828260408b20015460a81c1615611be657878952808752604089208281015460a01c84161561195b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bce5761198c8160005260096020526001600160a01b0360406000205416331490565b15611bae5761199a816136b5565b818a528289526119af600260408c20016134dd565b906001600160801b0395868351168783161015611b9657838c52848b5260408c205460f01c1615611b7e5791818a611a0085898f9a9998966119f68c998387935116613220565b9501511690613220565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b65575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaa8b85886140d7565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b0e575b5050505050506001019291906118ec565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b51575b80808080611afd565b611b5a90613105565b610524578438611b48565b818601600160a01b60ff60a01b19825416179055611a65565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c1c613939565b8183526009815260ff600160408520015460a81c1615611e0d57611c3f8261376d565b6005811015611df95760048103611c685760248360405190634a5541ef60e01b82526004820152fd5b60038103611c88576024836040519063fe19f19f60e01b82526004820152fd5b600214611de157611caf8260005260096020526001600160a01b0360406000205416331490565b15611dc2578183526009815260ff604084205460f01c1615611daa57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d52575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d96575b80611d23565b611d9f90613105565b61049c578238611d90565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ef5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee15760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f85613073565b9080546001600160a01b0380821693338503611fd7576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612020613073565b16801561203d578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061208d600435613692565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120b9613939565b604051906120c682613119565b6120ce613073565b82526120d8613089565b60208301526120e56131e6565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361126757608084015260a43580151581036112675760a084015260603660c319011261064c575060405161213f81613136565b64ffffffffff60c435818116810361126757825260e435818116810361126757602083015261010435908116810361126757604082015260c083015260406101231936011261126757604051916121958361318c565b610124359182168203611267578261125f9260209452610144358482015260e08201526139fe565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f09036906004016130d4565b90916024359081116104a05761220a9036906004016130d4565b612212613939565b80830361261657845b838110612226578580f35b612231818587613498565b359061223e818688613498565b35875260036020526001600160a01b0360408820541661225f828587613498565b35906001600160801b038216820361126757612279613939565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125fe5783895260036020526001600160a01b0360408a2054169182821415806125ee575b6125ca576122f1856140ac565b6001600160801b0381166001600160801b0383161161259a5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123828c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123a68160208401511692826040818351169201511690613220565b161115612569575b86855260096020526001600160a01b036001604087200154166123db6001600160801b03841685836140d7565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061255f575b6124f5575b8333141590816124ea575b816124df575b5061246d575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161221b565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c7575b8080612436565b6124d090613105565b6124db5786386124c0565b8680fd5b905083141538612430565b843b1515915061242a565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161254b575b505061241f565b61255490613105565b610524578438612544565b50803b151561241a565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123ae565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f885613995565b156122e4565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e1602091614133565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57806126c38361376d565b926005841015611880576002602094036126e4575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126d8565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612744613939565b8183526009815260ff600160408520015460a81c1615611e0d578183526009815260ff600160408520015460a01c16156128cf5761278182613995565b15611dc25781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128c5575b50806128bd575b6128a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612852575080f35b60249060405190637e27328960e01b82526004820152fd5b61288b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612800565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c0565b90501515386127b9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c5761290f3661309f565b60405191602083019383851067ffffffffffffffff86111761293a5761108294604052858452613525565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c1613939565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a0f5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bce57612a3a8160005260096020526001600160a01b0360406000205416331490565b15611bae57612a48816136b5565b93818452808352612a5e600260408620016134dd565b916001600160801b0393848451168588161015611de15781865282815260ff604087205460f01c1615611daa57612aac878683612aa28a9b838a9c9b9c5116613220565b9701511690613220565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c05575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b388c84876140d7565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb4578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bf6575b81818080808480f35b612bff90613105565b81612bed565b60018101600160a01b60ff60a01b19825416179055612af1565b503461064c57611082612c313661309f565b9161324f565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c8e9061376d565b90600582101561156a5760208215838115612caf575b506040519015158152f35b600191501482612ca4565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57602091604082828152600985522060ff815460f01c1680612d48575b612d1f575b50506001600160801b0360405191168152f35b612d4192506001600160801b036002612d3b92015416916136b5565b90613220565b3880612d0c565b5060ff600182015460a01c1615612d07565b503461064c57604036600319011261064c57612d74613073565b602435612d8081613692565b33151580612e40575b80612e16575b612de65781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d8f565b50336001600160a01b0382161415612d89565b503461064c57602036600319011261064c57602061208d6004356131fc565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f2d575b602095868610811461148257858852879493929187908215611460575050600114612ed35750506113f2925003836131a8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f155750506113f2935082010138806113e4565b80548389018501528794508693909201918101612efd565b93607f1693612ea0565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613001575b8115612fd7575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd0565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fc9565b60005b83811061303e5750506000910152565b818101518382015260200161302e565b906020916130678151809281855285808601910161302b565b601f01601f1916010190565b600435906001600160a01b038216820361126757565b602435906001600160a01b038216820361126757565b6060906003190112611267576001600160a01b0390600435828116810361126757916024359081168103611267579060443590565b9181601f840112156112675782359167ffffffffffffffff8311611267576020808501948460051b01011161126757565b67ffffffffffffffff811161293a57604052565b610100810190811067ffffffffffffffff82111761293a57604052565b6060810190811067ffffffffffffffff82111761293a57604052565b610180810190811067ffffffffffffffff82111761293a57604052565b610140810190811067ffffffffffffffff82111761293a57604052565b6040810190811067ffffffffffffffff82111761293a57604052565b90601f8019910116810190811067ffffffffffffffff82111761293a57604052565b67ffffffffffffffff811161293a57601f01601f191660200190565b604435906001600160801b038216820361126757565b61320581613692565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348057600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613476575b508061346e575b6134575786855260038152828486205416948733151593846133a7575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761336f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133415750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339082600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132dd565b91929380915090613416575b156133c157908783926132b4565b8488876133de576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b50338614801561343b575b806133b357508782526005835233848684205416146133b3565b5085825260068352848220338352835260ff8583205416613421565b602487855190630da9b01360e01b82526004820152fd5b506001613297565b9050151538613290565b6024604051633250574960e11b815260006004820152fd5b91908110156134a85760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134cb82613136565b60006040838281528260208201520152565b906040516134ea81613136565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112675790565b919061353282828561324f565b803b61353f575b50505050565b61359b6001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061304e565b03906020816000938185885af190829082613631575b50506135e857826135c061407c565b80519190826135e15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613619575038808080613539565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368a575b8161364e602093836131a8565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b1565b3d9150613641565b8060005260036020526001600160a01b0360406000205416908115612852575090565b600090808252600a60205264ffffffffff918260408220541642106137675760096020526040812092835490808260c81c169182421015613751576137069394955060a01c168091039042036142f6565b9082815260096020526001600160801b039261372c8460026040852001541680946143d6565b9283116137395750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613794575050600490565b805460f81c6137ed575460a01c64ffffffffff1642106137e7576137b7816136b5565b9060005260096020526001600160801b0380600260406000200154169116106000146137e257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c1615908161392f575b5080613924575b61390d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138d5575b1692836138bf575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b838752600488528087206001815401905561389b565b6138f686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613893565b602486885190630da9b01360e01b82526004820152fd5b508181161515613832565b905015153861382b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139da575b505082156139c857505090565b9091506139d533926131fc565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139bb565b90613a1f6001600160801b03604084015116602060e08501510151906141ae565b916001600160801b0383511660c082015190156140525764ffffffffff815116156140285764ffffffffff81511690604081019164ffffffffff8351169081811015613fe8575050602081019064ffffffffff8251169081151580613fd6575b613f9557505064ffffffffff90511664ffffffffff8251169081811015613f5557505064ffffffffff8042169151169081811015613f15575050600754926001600160801b0381511660405190613ad582613136565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613b378861316f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d2f84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613ef7575b50600184016007556001600160a01b03602083015116801561348057613d7f856001600160a01b03926137f4565b16613ec657613daa6001600160a01b036060840151166001600160801b038351169030903390614287565b6001600160801b0360208201511680613e97575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613e8e6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613ec0906001600160a01b036060850151166001600160a01b0360e08601515116903390614287565b38613dbe565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613d51565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613a7f565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d156140a7573d9061408d826131ca565b9161409b60405193846131a8565b82523d6000602084013e565b606090565b6140d4906140b981614133565b90600052600960205260026040600020015460801c90613220565b90565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141319161412c6064836131a8565b614485565b565b80600052600960205261414c60026040600020016134dd565b816000526009602052604060002060ff600182015460a01c1660001461417f57506001600160801b039150602001511690565b5460f81c61419157506140d4906136b5565b6140d491506001600160801b036040818351169201511690613220565b919091604051906141be8261318c565b600091828152826020820152936001600160801b03928383169182156142685767016345785d8a000080821161423157506141fa8591846143d6565b166020870192818452111561421d5750908261421892511690613220565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061427c8261318c565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293a5761413192604052614485565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b2578285101561437657908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c0570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447457670de0b6b3a7640000908183101561443d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b0600080836020829551910182875af16144a961407c565b9084614521565b9081519182151592836144f9575b5050506144c85750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144be565b90614560575080511561453657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145ab575b614571575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456956fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f6200499e3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c19081620003dd8239608051816139430152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5a57508063027b674414612f3757806306fdde0314612e72578063081812fc14612e53578063095ea7b314612d5a5780631400ecec14612cba5780631c1cdd4c14612c555780631e99d56914612c3757806323b872dd14612c1f57806340e58ee5146129a1578063425d30dd1461295057806342842e0e1461290057806342966c681461272557806344267570146126fe5780634857501f146126885780634869e12d1461264d5780634cc55e11146121bd57806353b157271461209e5780636352211e1461206e5780636d0cee751461206e57806370a0823114611ffe57806375829def14611f6b578063780a82c814611f1e5780637cad6cd114611e245780637de6b1db14611bfd5780638659c270146118ac578063894e9a0d1461158c5780638f69b993146114f05780639067b677146114a057806395d89b4114611391578063a22cb465146112d4578063a80fc07114611282578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613089565b916102786131e6565b92610281613939565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a7576103038961412a565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134dd565b906103b181868401511692826040818351169201511690613220565b161115610532575b848c528252600160408c20015416946103d3818a88614152565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613105565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613105565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613995565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613089565b916102788161412a565b503461064c57604036600319011261064c5761076b613073565b6040610775613089565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e160209161412a565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134be565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613136565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613692565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061304e565b0390f35b909192503d8082843e6109fd81846131a8565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131ca565b93610a4160405195866131a8565b83855285848401011161064c575090610a5f9184808501910161302b565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613089565b610a9c613939565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae38661412a565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f4565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613939565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a61412a565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613220565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb6818688614152565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c90613105565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e0090613105565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613995565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613073565b61101a613089565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131ca565b9361105760405195866131a8565b8585523660248783010111610a67578561108296602460209301838801378501015260443591613525565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061376d565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613939565b61115b6134be565b9064ffffffffff80421680845281611171613511565b1661126c575b60e4359082821682036112675701166040830152600435916001600160a01b0391828416809403611267576024359083821680920361126757604435906001600160801b038216809203611267576064359085821680920361064c5750608435918215158093036112675760a4359384151580950361126757604051976111fd89613119565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126757604051916112378361318c565b610104359182168203611267578261125f9260209452610124358482015260e0820152613a7c565b604051908152f35b600080fd5b81611275613511565b8201166020850152611177565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112ee613073565b60243590811515809203611267576001600160a01b03169081156113605733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c9260018516948515611496575b602095868610811461148257858852879493929187908215611460575050600114611406575b50506113f2925003836131a8565b6109e660405192828493845283019061304e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106114485750506113f2935082010138806113e4565b80548389018501528794508693909201918101611430565b92509350506113f294915060ff191682840152151560051b82010138806113e4565b602483634e487b7160e01b81526022600452fd5b93607f16936113be565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576115299061376d565b906005821015908161156a576002831491821561157e575b8215611555575b6020836040519015158152f35b90915061156a57506004602091143880611548565b80634e487b7160e01b602492526021600452fd5b506003831491506000611541565b503461064c57602036600319011261064c57806101606040516115ae81613152565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f16134be565b61014082015201526004358152600960205260ff600160408320015460a81c1615611894576004358152600960205260408120906116bf6002604051936116378561316f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134dd565b6101208301526116d060043561376d565b6005811015611880576101606101c093600264ffffffffff9314611875575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b61177c8d613152565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116ef565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118df9036906004016130d4565b91906118e9613939565b83925b8084106118f7578480f35b611902848284613498565b359361190c613939565b848652600980855260ff90600190828260408b20015460a81c1615611be657878952808752604089208281015460a01c84161561195b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bce5761198c8160005260096020526001600160a01b0360406000205416331490565b15611bae5761199a816136b5565b818a528289526119af600260408c20016134dd565b906001600160801b0395868351168783161015611b9657838c52848b5260408c205460f01c1615611b7e5791818a611a0085898f9a9998966119f68c998387935116613220565b9501511690613220565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b65575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaa8b8588614152565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b0e575b5050505050506001019291906118ec565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b51575b80808080611afd565b611b5a90613105565b610524578438611b48565b818601600160a01b60ff60a01b19825416179055611a65565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c1c613939565b8183526009815260ff600160408520015460a81c1615611e0d57611c3f8261376d565b6005811015611df95760048103611c685760248360405190634a5541ef60e01b82526004820152fd5b60038103611c88576024836040519063fe19f19f60e01b82526004820152fd5b600214611de157611caf8260005260096020526001600160a01b0360406000205416331490565b15611dc2578183526009815260ff604084205460f01c1615611daa57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d52575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d96575b80611d23565b611d9f90613105565b61049c578238611d90565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ef5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee15760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f85613073565b9080546001600160a01b0380821693338503611fd7576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612020613073565b16801561203d578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061208d600435613692565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120b9613939565b604051906120c682613119565b6120ce613073565b82526120d8613089565b60208301526120e56131e6565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361126757608084015260a43580151581036112675760a084015260603660c319011261064c575060405161213f81613136565b64ffffffffff60c435818116810361126757825260e435818116810361126757602083015261010435908116810361126757604082015260c083015260406101231936011261126757604051916121958361318c565b610124359182168203611267578261125f9260209452610144358482015260e0820152613a7c565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f09036906004016130d4565b90916024359081116104a05761220a9036906004016130d4565b612212613939565b80830361261657845b838110612226578580f35b612231818587613498565b359061223e818688613498565b35875260036020526001600160a01b0360408820541661225f828587613498565b35906001600160801b038216820361126757612279613939565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125fe5783895260036020526001600160a01b0360408a2054169182821415806125ee575b6125ca576122f18561412a565b6001600160801b0381166001600160801b0383161161259a5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123828c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123a68160208401511692826040818351169201511690613220565b161115612569575b86855260096020526001600160a01b036001604087200154166123db6001600160801b0384168583614152565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061255f575b6124f5575b8333141590816124ea575b816124df575b5061246d575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161221b565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c7575b8080612436565b6124d090613105565b6124db5786386124c0565b8680fd5b905083141538612430565b843b1515915061242a565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161254b575b505061241f565b61255490613105565b610524578438612544565b50803b151561241a565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123ae565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f885613995565b156122e4565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916139fe565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57806126c38361376d565b926005841015611880576002602094036126e4575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126d8565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612744613939565b8183526009815260ff600160408520015460a81c1615611e0d578183526009815260ff600160408520015460a01c16156128cf5761278182613995565b15611dc25781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128c5575b50806128bd575b6128a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612852575080f35b60249060405190637e27328960e01b82526004820152fd5b61288b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612800565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c0565b90501515386127b9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c5761290f3661309f565b60405191602083019383851067ffffffffffffffff86111761293a5761108294604052858452613525565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c1613939565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a0f5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bce57612a3a8160005260096020526001600160a01b0360406000205416331490565b15611bae57612a48816136b5565b93818452808352612a5e600260408620016134dd565b916001600160801b0393848451168588161015611de15781865282815260ff604087205460f01c1615611daa57612aac878683612aa28a9b838a9c9b9c5116613220565b9701511690613220565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c05575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b388c8487614152565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb4578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bf6575b81818080808480f35b612bff90613105565b81612bed565b60018101600160a01b60ff60a01b19825416179055612af1565b503461064c57611082612c313661309f565b9161324f565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c8e9061376d565b90600582101561156a5760208215838115612caf575b506040519015158152f35b600191501482612ca4565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57602091604082828152600985522060ff815460f01c1680612d48575b612d1f575b50506001600160801b0360405191168152f35b612d4192506001600160801b036002612d3b92015416916136b5565b90613220565b3880612d0c565b5060ff600182015460a01c1615612d07565b503461064c57604036600319011261064c57612d74613073565b602435612d8081613692565b33151580612e40575b80612e16575b612de65781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d8f565b50336001600160a01b0382161415612d89565b503461064c57602036600319011261064c57602061208d6004356131fc565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f2d575b602095868610811461148257858852879493929187908215611460575050600114612ed35750506113f2925003836131a8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f155750506113f2935082010138806113e4565b80548389018501528794508693909201918101612efd565b93607f1693612ea0565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613001575b8115612fd7575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd0565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fc9565b60005b83811061303e5750506000910152565b818101518382015260200161302e565b906020916130678151809281855285808601910161302b565b601f01601f1916010190565b600435906001600160a01b038216820361126757565b602435906001600160a01b038216820361126757565b6060906003190112611267576001600160a01b0390600435828116810361126757916024359081168103611267579060443590565b9181601f840112156112675782359167ffffffffffffffff8311611267576020808501948460051b01011161126757565b67ffffffffffffffff811161293a57604052565b610100810190811067ffffffffffffffff82111761293a57604052565b6060810190811067ffffffffffffffff82111761293a57604052565b610180810190811067ffffffffffffffff82111761293a57604052565b610140810190811067ffffffffffffffff82111761293a57604052565b6040810190811067ffffffffffffffff82111761293a57604052565b90601f8019910116810190811067ffffffffffffffff82111761293a57604052565b67ffffffffffffffff811161293a57601f01601f191660200190565b604435906001600160801b038216820361126757565b61320581613692565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348057600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613476575b508061346e575b6134575786855260038152828486205416948733151593846133a7575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761336f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133415750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339082600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132dd565b91929380915090613416575b156133c157908783926132b4565b8488876133de576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b50338614801561343b575b806133b357508782526005835233848684205416146133b3565b5085825260068352848220338352835260ff8583205416613421565b602487855190630da9b01360e01b82526004820152fd5b506001613297565b9050151538613290565b6024604051633250574960e11b815260006004820152fd5b91908110156134a85760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134cb82613136565b60006040838281528260208201520152565b906040516134ea81613136565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112675790565b919061353282828561324f565b803b61353f575b50505050565b61359b6001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061304e565b03906020816000938185885af190829082613631575b50506135e857826135c06140fa565b80519190826135e15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613619575038808080613539565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368a575b8161364e602093836131a8565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b1565b3d9150613641565b8060005260036020526001600160a01b0360406000205416908115612852575090565b600090808252600a60205264ffffffffff918260408220541642106137675760096020526040812092835490808260c81c169182421015613751576137069394955060a01c168091039042036142f6565b9082815260096020526001600160801b039261372c8460026040852001541680946143d6565b9283116137395750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613794575050600490565b805460f81c6137ed575460a01c64ffffffffff1642106137e7576137b7816136b5565b9060005260096020526001600160801b0380600260406000200154169116106000146137e257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c1615908161392f575b5080613924575b61390d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138d5575b1692836138bf575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b838752600488528087206001815401905561389b565b6138f686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613893565b602486885190630da9b01360e01b82526004820152fd5b508181161515613832565b905015153861382b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139da575b505082156139c857505090565b9091506139d533926131fc565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139bb565b806000526009602052613a1760026040600020016134dd565b816000526009602052604060002060ff600182015460a01c16600014613a4a57506001600160801b039150602001511690565b5460f81c613a5f5750613a5c906136b5565b90565b613a5c91506001600160801b036040818351169201511690613220565b90613a9d6001600160801b03604084015116602060e08501510151906141ae565b916001600160801b0383511660c082015190156140d05764ffffffffff815116156140a65764ffffffffff81511690604081019164ffffffffff8351169081811015614066575050602081019064ffffffffff8251169081151580614054575b61401357505064ffffffffff90511664ffffffffff8251169081811015613fd357505064ffffffffff8042169151169081811015613f93575050600754926001600160801b0381511660405190613b5382613136565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb58861316f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dad84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f75575b50600184016007556001600160a01b03602083015116801561348057613dfd856001600160a01b03926137f4565b16613f4457613e286001600160a01b036060840151166001600160801b038351169030903390614287565b6001600160801b0360208201511680613f15575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0c6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3e906001600160a01b036060850151166001600160a01b0360e08601515116903390614287565b38613e3c565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dcf565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613afd565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614125573d9061410b826131ca565b9161411960405193846131a8565b82523d6000602084013e565b606090565b613a5c90614137816139fe565b90600052600960205260026040600020015460801c90613220565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ac916141a76064836131a8565b614485565b565b919091604051906141be8261318c565b600091828152826020820152936001600160801b03928383169182156142685767016345785d8a000080821161423157506141fa8591846143d6565b166020870192818452111561421d5750908261421892511690613220565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061427c8261318c565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293a576141ac92604052614485565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b2578285101561437657908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c0570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447457670de0b6b3a7640000908183101561443d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b0600080836020829551910182875af16144a96140fa565b9084614521565b9081519182151592836144f9575b5050506144c85750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144be565b90614560575080511561453657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145ab575b614571575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456956fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004dff3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149fd908162000402823960805181613dda015260a051818181612eb80152613e800152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613dd0565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f896145ad565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c90610343916145d8565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a8861473d565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614514565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b91610749816145ad565b92610752613dd0565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f896145ad565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b8576108936020916145ad565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613dd0565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b62866145ad565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c8b565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613dd0565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a6145ad565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c6145d8565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d3381868861473d565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a614514565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613c04565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613c04565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613dd0565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613e2c565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613c04565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613dd0565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613dd0565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b858861473d565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613dd0565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613c04565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613dd0565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613dd0565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b856145ad565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c6145d8565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b038416858361473d565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b5061271785614514565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614797565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613c04565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613dd0565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a082614514565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613dd0565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c848761473d565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613dd0565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613c04565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc61457d565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff80421691600090808252602091600a602052613b166040822061386e565b9185856020613b2486613ad1565b5101511611613bfb5781526009602052604081208585825460c81c161115613be557506001600160801b039485613b5a84613ad1565b5151169583519260019360011015613bd15750949392919084602060408501510151169581866001985b161115613b95575050505050505090565b909181879881613ba98798999a8598613ade565b5151160116970191868087613bbe8689613ade565b5101511697829392919796959498613b84565b80634e487b7160e01b602492526032600452fd5b600201546001600160801b031695945050505050565b50935050505090565b806000526009602052604060002060ff600182015460a01c16600014613c2b575050600490565b805460f81c613c84575460a01c64ffffffffff164210613c7e57613c4e81613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c7957600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613dc6575b5080613dbb575b613da4579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d6c575b169283613d56575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d32565b613d8d86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d2a565b602486885190630da9b01360e01b82526004820152fd5b508181161515613cc9565b9050151538613cc2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e0257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e4e6001600160801b0360408401511660206101008501510151906145f3565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144ea5780156144c05781518015614496577f00000000000000000000000000000000000000000000000000000000000000008111614465575064ffffffffff6020613eb784613ad1565b5101511681101561440e5750600090819082815184905b80821061437d575050505064ffffffffff421664ffffffffff821681101561433d5750506001600160801b0316808203614306575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406a8951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b818110614261575050600185016007556001600160a01b03602083015116801561378d576140b7866001600160a01b0392613c8b565b16614230576140e26001600160a01b036060840151166001600160801b0383511690309033906146cc565b6001600160801b0360208201511680614200575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141f56141d660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a61417f8c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61422a906001600160a01b036060850151166001600160a01b0361010086015151169033906146cc565b386140f6565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a60205260406000209061427e8160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614081565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143a1906001600160801b036143988588613ade565b515116906145d8565b9364ffffffffff8060206143b58685613ade565b510151169416808511156143d157506001849301909291613ece565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061441f84613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614559575b5050821561454757505090565b9091506145543392613509565b161490565b60ff929450906040918152600660205281812033825260205220541691388061453a565b3d156145a8573d9061458e826134d9565b9161459c60405193846134b7565b82523d6000602084013e565b606090565b6145d5906145ba81614797565b90600052600960205260026040600020015460801c9061352d565b90565b9190916001600160801b038080941691160191821161354657565b919091604051906146038261349b565b600091828152826020820152936001600160801b03928383169182156146ad5767016345785d8a0000808211614676575061463f8591846148ae565b16602087019281845211156146625750908261465d9251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146c18261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761473b92604052614812565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261473b916147926064836134b7565b614812565b8060005260096020526147b060026040600020016138ec565b816000526009602052604060002060ff600182015460a01c166000146147e357506001600160801b039150602001511690565b5460f81c6147f557506145d590613af2565b6145d591506001600160801b03604081835116920151169061352d565b6001600160a01b03169061483d600080836020829551910182875af161483661457d565b908461495d565b908151918215159283614886575b5050506148555750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061484b565b9091906000198382098382029182808310920391808303921461494c57670de0b6b3a7640000908183101561491557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061499c575080511561497257805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149e7575b6149ad575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149a556fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004dc23881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556149c0908162000402823960805181613da2015260a051818181612eb80152613e480152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461321657508063027b6744146131f357806306fdde031461312e578063081812fc1461310f578063095ea7b3146130165780631400ecec14612f765780631c1cdd4c14612f115780631e99d56914612ef357806323b872dd14612edb5780632fe4304114612ea057806332fbe22b14612d4857806340e58ee514612aaa578063425d30dd14612a5957806342842e0e14612a1f57806342966c6814612844578063442675701461281d5780634857501f146127a75780634869e12d1461276c5780634cc55e11146122f05780636352211e146122c05780636d0cee75146122c057806370a082311461225057806375829def146121bd5780637cad6cd1146120c35780637de6b1db14611e9c5780637f5799f914611e415780638659c27014611ae7578063894e9a0d1461175b578063897f362b146114ab5780638f69b9931461140f5780639067b677146113bf57806395d89b41146112b0578063a22cb465146111f3578063a80fc071146111a1578063ad35efd41461113f578063b2564569146110ee578063b88d4fde14611061578063b8a3be661461102c578063b971302a14610fdd578063bc2be1be14610f8d578063c156a11d14610af6578063c87b56dd146109da578063cc364f4814610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610803578063ea5ead1914610721578063eac8f5b8146106cf578063f590c1761461066d578063f851a440146106475763fdd46d601461025d57600080fd5b34610644576060366003190112610644576004359061027a613345565b91604435926001600160801b038085169182860361063f5761029a613d98565b83855260099560209387855260ff600160408920015460a81c16156106285785875287855260ff600160408920015460a01c16610610576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f896145f3565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c906103439161461b565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155610379906138ec565b908084830151169181808251169160400151166103959161352d565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a88614780565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b6104989061344e565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b6105209061344e565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c8896144dc565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106445780600319360112610644576001600160a01b036020915416604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610644576040366003190112610644576004359061073f613345565b91610749816145f3565b92610752613d98565b81835260099360209185835260ff600160408720015460a81c16156107ec5783855285835260ff600160408720015460a01c166107d4576001600160a01b03918282169283156105e6576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f896145f3565b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b50346106445760403660031901126106445761081d61332f565b6040610827613345565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b8576108936020916145f3565b6001600160801b0360405191168152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082600292602094526009845220015460801c604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760036040836001600160801b0393602095526009855220015416604051908152f35b503461064457602036600319011261064457600435600060206040516109678161349b565b8281520152808252600960205260ff600160408420015460a81c16156106b857604082819281526009602052205464ffffffffff8251916109a78361349b565b818160a01c16835260c81c1660208201526109d8825180926020908164ffffffffff91828151168552015116910152565bf35b503461064457602080600319360112610ae6576004356109f981613aae565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610aea578093610a69575b5050610a6560405192828493845283019061330a565b0390f35b909192503d8082843e610a7c81846134b7565b8201918381840312610ae65780519067ffffffffffffffff82116104a3570182601f82011215610ae657805191610ab2836134d9565b93610ac060405195866134b7565b838552858484010111610644575090610ade918480850191016132e7565b903880610a4f565b5080fd5b604051903d90823e3d90fd5b503461064457604036600319011261064457600435610b13613345565b610b1b613d98565b81835260099060209082825260ff600160408720015460a81c16156107ec57838552600382526001600160a01b03918260408720541693843303610f6e57610b62866145f3565b906001600160801b039081831680158015610c02575b50505050505081811615610bea5783610b9091613c53565b90811680610bb05760248460405190637e27328960e01b82526004820152fd5b8203610bba578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c0a613d98565b898b5282865260ff600160408d20015460a81c1615610f5757898b5282865260ff600160408d20015460a01c16610f3f5788156105e657610f2757888a52600385528660408b205416918289141580610f17575b610ef357610c6b8a6145f3565b8481168311610ec15750908a949392918a86528087526040862093610cd0610c9e8760028d89541698015460801c61461b565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b1691161781556138ec565b90610cec818a840151169282604081835116920151169061352d565b161115610e92575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d33818688614780565b604051908152a48033141580610e88575b610e1e575b813314159081610e13575b81610e08575b50610d97575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b78565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df0575b80610d60565b610df99061344e565b610e04578538610dea565b8580fd5b905081141538610d5a565b823b15159150610d54565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e74575b5050610d49565b610e7d9061344e565b6104a7578338610e6d565b50803b1515610d44565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cf4565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f218a6144dc565b15610c5e565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b8576040826001600160a01b03926020945260098452205416604051908152f35b50346106445760203660031901126106445760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346106445760803660031901126106445761107b61332f565b611083613345565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110b2856134d9565b936110c060405195866134b7565b8585523660248783010111610ae657856110eb96602460209301838801378501015260443591613941565b80f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761117890613bcc565b60405190600581101561118d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760026040836001600160801b0393602095526009855220015416604051908152f35b50346106445760403660031901126106445761120d61332f565b6024359081151580920361063f576001600160a01b031690811561127f5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457806003193601126106445760405190806002549160018360011c92600185169485156113b5575b60209586861081146113a15785885287949392918790821561137f575050600114611325575b5050611311925003836134b7565b610a6560405192828493845283019061330a565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061136757505061131193508201013880611303565b8054838901850152879450869390920191810161134f565b925093505061131194915060ff191682840152151560051b8201013880611303565b602483634e487b7160e01b81526022600452fd5b93607f16936112dd565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b85761144890613bcc565b9060058210159081611489576002831491821561149d575b8215611474575b6020836040519015158152f35b90915061148957506004602091143880611467565b80634e487b7160e01b602492526021600452fd5b506003831491506000611460565b5034610644576020906003198281360112610ae6576004359167ffffffffffffffff91828411610ae65761012084360391820112610ae6576114eb613d98565b60c48401359060221901811215610ae65783016004810135928311610ae65760248101908360061b80360383136104a757602490611528866137b7565b9561153660405197886134b7565b8652878601920101913683116104a757905b868383106117435750505050815190611560826137b7565b9261156e60405194856134b7565b828452601f1961157d846137b7565b0186835b82811061171f5750505064ffffffffff804216936001600160801b0392836115a882613ad1565b51511683808b6115b785613ad1565b51015116880116604051916115cb8361349b565b82528a8201526115da88613ad1565b526115e487613ad1565b5060019260015b8381106116b657505050505061160385600401613920565b9161161060248701613920565b9161161d6044880161385a565b6064880135926001600160a01b039081851680950361064457509288959261166e9895926116a3989561165560846116ae9d01613934565b948161166360a48c01613934565b976040519d8e613431565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613805565b610100820152613df4565b604051908152f35b8089838d8180826116db8d6116cc8e9a8d613ade565b51511696600019890190613ade565b51015116916116ea868a613ade565b510151160116604051916116fd8361349b565b82528d82015261170d828c613ade565b52611718818b613ade565b50016115eb565b60405161172b8161349b565b60008152600083820152828289010152018790611581565b60409161175036856137cf565b815201910190611548565b503461064457602036600319011261064457606061016060405161177e81613462565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117c48161347f565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611acf5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ab9576118b59160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016138ec565b6101208301526118c6600435613bcc565b6005811015611aa557610160926119719260026119ad9314611a9a575b610120820151906001600160a01b0360a0840151169064ffffffffff60408501511660608501511515928561010081015115159460c082015115159360e0830151151595600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613462565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e087015261010086015261012085015261014084015261386e565b82820152610a65604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e08301906133d5565b8060608301526118e3565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064457602080600319360112610ae65760043567ffffffffffffffff81116104a357611b1a9036906004016133a4565b9190611b24613d98565b83925b808410611b32578480f35b611b3d848284613834565b3593611b47613d98565b848652600980855260ff90600190828260408b20015460a81c1615611e2a57878952808752604089208281015460a01c841615611b965760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e1257611bc78160005260096020526001600160a01b0360406000205416331490565b15611df257611bd581613af2565b818a52828952611bea600260408c20016138ec565b906001600160801b0395868351168783161015611dda57838c52848b5260408c205460f01c1615611dc25791818a611c3b85898f9a999896611c318c99838793511661352d565b950151169061352d565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611da9575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611cee8b8588614780565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d52575b505050505050600101929190611b27565b813b15610e0457856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d95575b80808080611d41565b611d9e9061344e565b61052b578438611d8c565b818601600160a01b60ff60a01b19825416179055611ca0565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857604082611e8892610a659452600a6020522061386e565b6040519182916020835260208301906133d5565b503461064457602080600319360112610ae65760043590611ebb613d98565b8183526009815260ff600160408520015460a81c16156120ac57611ede82613bcc565b60058110156120985760048103611f075760248360405190634a5541ef60e01b82526004820152fd5b60038103611f27576024836040519063fe19f19f60e01b82526004820152fd5b60021461208057611f4e8260005260096020526001600160a01b0360406000205416331490565b15612061578183526009815260ff604084205460f01c161561204957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611ff1575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612035575b80611fc2565b61203e9061344e565b6104a357823861202f565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610644576020366003190112610644576004356001600160a01b03908181168091036104a35781835416338103612194575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121805760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610644576020366003190112610644576121d761332f565b9080546001600160a01b0380821693338503612229576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610644576020366003190112610644576001600160a01b0361227261332f565b16801561228f578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106445760203660031901126106445760206122df600435613aae565b6001600160a01b0360405191168152f35b50346106445760403660031901126106445767ffffffffffffffff6004358181116104a3576123239036906004016133a4565b90916024359081116104a75761233d9036906004016133a4565b612345613d98565b80830361273557845b838110612359578580f35b612364818587613834565b3590612371818688613834565b35875260036020526001600160a01b0360408820541661239a612395838688613834565b61385a565b906123a3613d98565b838952600960205260ff600160408b20015460a81c16156107ec57838952600960205260ff600160408b20015460a01c166107d45780156105e6576001600160801b0382161561271d5783895260036020526001600160a01b0360408a20541691828214158061270d575b6126e95761241b856145f3565b6001600160801b0381166001600160801b038316116126b9575090899291858452600960205260408420926124a16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961248387608094851c61461b565b938c8b52600960205260408b2001938454931b1691161781556138ec565b6001600160801b036124c5816020840151169282604081835116920151169061352d565b161115612688575b86855260096020526001600160a01b036001604087200154166124fa6001600160801b0384168583614780565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061267e575b612614575b833314159081612609575b816125fe575b5061258c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161234e565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125e6575b8080612555565b6125ef9061344e565b6125fa5786386125df565b8680fd5b90508314153861254f565b843b15159150612549565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161266a575b505061253e565b6126739061344e565b61052b578438612663565b50803b1515612539565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124cd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b50612717856144dc565b1561240e565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106445760203660031901126106445760ff6001604060043593848152600960205220015460a81c16156106b857610893602091614545565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57806127e283613bcc565b926005841015611aa557600260209403612803575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806127f7565b503461064457806003193601126106445760206001600160a01b0360085416604051908152f35b503461064457602080600319360112610ae65760043590612863613d98565b8183526009815260ff600160408520015460a81c16156120ac578183526009815260ff600160408520015460a01c16156129ee576128a0826144dc565b156120615781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816129e4575b50806129dc575b6129c4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612989575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612971575080f35b60249060405190637e27328960e01b82526004820152fd5b6129aa85600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561291f565b60248360405190630da9b01360e01b82526004820152fd5b5060006128df565b90501515386128d8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064457612a2e3661336f565b60405191602083019383851067ffffffffffffffff861117611ab9576110eb94604052858452613941565b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064457602090816003193601126106445760043590612aca613d98565b81815260099283815260ff600160408420015460a81c1615612d315782825283815260408220600181015460a01c60ff1615612b185760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e1257612b438160005260096020526001600160a01b0360406000205416331490565b15611df257612b5181613af2565b93818452808352612b67600260408620016138ec565b916001600160801b03938484511685881610156120805781865282815260ff604087205460f01c161561204957612bb5878683612bab8a9b838a9c9b9c511661352d565b970151169061352d565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d17575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612c4a8c8487614780565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612cc6578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d08575b81818080808480f35b612d119061344e565b81612cff565b60018101600160a01b60ff60a01b19825416179055612bfa565b6024836040519062b8e7e760e51b82526004820152fd5b5034610644576003199060203683018113610ae6576004359167ffffffffffffffff93848411610ae65761014090843603011261064457612d87613d98565b60405193612d9485613431565b612da08460040161335b565b8552612dae6024850161335b565b6020860152612dbf604485016134f5565b604086015260648401356001600160a01b03811681036104a3576060860152612dea60848501613424565b6080860152612dfb60a48501613424565b60a0860152612e0c60c485016137a5565b60c086015260e4840135908111610ae65783019136602384011215610ae6576004830135612e39816137b7565b93612e4760405195866134b7565b8185526024602086019260061b820101933685116106445750602401905b838210612e875760206116ae886116a3898960e0840152610104369101613805565b82604091612e9536856137cf565b815201910190612e65565b503461064457806003193601126106445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610644576110eb612eed3661336f565b9161355c565b50346106445780600319360112610644576020600754604051908152f35b503461064457602036600319011261064457600435808252600960205260ff600160408420015460a81c16156106b857612f4a90613bcc565b9060058210156114895760208215838115612f6b575b506040519015158152f35b600191501482612f60565b50346106445760203660031901126106445760043590818152600960205260ff600160408320015460a81c16156120ac57602091604082828152600985522060ff815460f01c1680613004575b612fdb575b50506001600160801b0360405191168152f35b612ffd92506001600160801b036002612ff79201541691613af2565b9061352d565b3880612fc8565b5060ff600182015460a01c1615612fc3565b50346106445760403660031901126106445761303061332f565b60243561303c81613aae565b331515806130fc575b806130d2575b6130a25781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff6040852054161561304b565b50336001600160a01b0382161415613045565b50346106445760203660031901126106445760206122df600435613509565b50346106445780600319360112610644576040519080600191600154928360011c92600185169485156131e9575b60209586861081146113a15785885287949392918790821561137f57505060011461318f575050611311925003836134b7565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8583106131d157505061131193508201013880611303565b805483890185015287945086939092019181016131b9565b93607f169361315c565b5034610644578060031936011261064457602060405167016345785d8a00008152f35b905034610ae6576020366003190112610ae6576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd0000000000000000000000000000000000000000000000000000000081149081156132bd575b8115613293575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861328c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613285565b60005b8381106132fa5750506000910152565b81810151838201526020016132ea565b90602091613323815180928185528580860191016132e7565b601f01601f1916010190565b600435906001600160a01b038216820361063f57565b602435906001600160a01b038216820361063f57565b35906001600160a01b038216820361063f57565b606090600319011261063f576001600160a01b0390600435828116810361063f5791602435908116810361063f579060443590565b9181601f8401121561063f5782359167ffffffffffffffff831161063f576020808501948460051b01011161063f57565b90815180825260208080930193019160005b8281106133f5575050505090565b835180516001600160801b0316865282015164ffffffffff1685830152604090940193928101926001016133e7565b3590811515820361063f57565b610120810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957604052565b610180810190811067ffffffffffffffff821117611ab957604052565b6060810190811067ffffffffffffffff821117611ab957604052565b6040810190811067ffffffffffffffff821117611ab957604052565b90601f8019910116810190811067ffffffffffffffff821117611ab957604052565b67ffffffffffffffff8111611ab957601f01601f191660200190565b35906001600160801b038216820361063f57565b61351281613aae565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161354657565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561378d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613783575b508061377b575b6137645786855260038152828486205416948733151593846136b4575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761367c575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361364e5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61369d82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556135ea565b91929380915090613723575b156136ce57908783926135c1565b8488876136eb576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613748575b806136c057508782526005835233848684205416146136c0565b5085825260068352848220338352835260ff858320541661372e565b602487855190630da9b01360e01b82526004820152fd5b5060016135a4565b905015153861359d565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361063f57565b67ffffffffffffffff8111611ab95760051b60200190565b919082604091031261063f576040516137e78161349b565b60206138008183956137f8816134f5565b8552016137a5565b910152565b919082604091031261063f5760405161381d8161349b565b602080829461382b8161335b565b84520135910152565b91908110156138445760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361063f5790565b90815461387a816137b7565b9260409361388b60405191826134b7565b82815280946020809201926000526020600020906000935b8585106138b257505050505050565b600184819284516138c28161349b565b64ffffffffff87546001600160801b038116835260801c16838201528152019301940193916138a3565b906040516138f98161347f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361063f5790565b35801515810361063f5790565b919061394e82828561355c565b803b61395b575b50505050565b6139b76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061330a565b03906020816000938185885af190829082613a4d575b5050613a0457826139dc6145c3565b80519190826139fd5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a35575038808080613955565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613aa6575b81613a6a602093836134b7565b81010312610ae65751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064457509038806139cd565b3d9150613a5d565b8060005260036020526001600160a01b0360406000205416908115612971575090565b8051156138445760200190565b80518210156138445760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b15604060002061386e565b9084846020613b2385613ad1565b5101511611613bc257600052600960205260406000208484825460c81c161115613bad57506001600160801b039081613b5b82613ad1565b515116946001948594855b613b75575b5050505050505090565b828282613b828a88613ade565b5101511611613ba8578585889981613b9b849b89613ade565b5151160116980196613b66565b613b6b565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613bf3575050600490565b805460f81c613c4c575460a01c64ffffffffff164210613c4657613c1681613af2565b9060005260096020526001600160801b038060026040600020015416911610600014613c4157600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613d8e575b5080613d83575b613d6c579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d34575b169283613d1e575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613cfa565b613d5586600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613cf2565b602486885190630da9b01360e01b82526004820152fd5b508181161515613c91565b9050151538613c8a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dca57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e166001600160801b036040840151166020610100850151015190614636565b6001600160801b0381511660e084015164ffffffffff60c08601511682156144b2578015614488578151801561445e577f0000000000000000000000000000000000000000000000000000000000000000811161442d575064ffffffffff6020613e7f84613ad1565b510151168110156143d65750600090819082815184905b808210614345575050505064ffffffffff421664ffffffffff82168110156143055750506001600160801b03168082036142ce575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140328951996000198b0190613ade565b51015160c81b169560f01b16911617171717845560005b818110614229575050600185016007556001600160a01b03602083015116801561378d5761407f866001600160a01b0392613c53565b166141f8576140aa6001600160a01b036060840151166001600160801b03835116903090339061470f565b6001600160801b03602082015116806141c8575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b03606082015116966141bd61419e60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141478c61349b565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c08801528601906133d5565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b6141f2906001600160a01b036060850151166001600160a01b03610100860151511690339061470f565b386140be565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142468160e0870151613ade565b51825468010000000000000000811015611ab9576001810180855581101561384457600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b1692161717905501614049565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193614369906001600160801b036143608588613ade565b5151169061461b565b9364ffffffffff80602061437d8685613ade565b5101511694168085111561439957506001849301909291613e96565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff60206143e784613ad1565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614521575b5050821561450f57505090565b90915061451c3392613509565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614502565b80600052600960205261455e60026040600020016138ec565b816000526009602052604060002060ff600182015460a01c1660001461459157506001600160801b039150602001511690565b5460f81c6145a657506145a390613af2565b90565b6145a391506001600160801b03604081835116920151169061352d565b3d156145ee573d906145d4826134d9565b916145e260405193846134b7565b82523d6000602084013e565b606090565b6145a39061460081614545565b90600052600960205260026040600020015460801c9061352d565b9190916001600160801b038080941691160191821161354657565b919091604051906146468261349b565b600091828152826020820152936001600160801b03928383169182156146f05767016345785d8a00008082116146b95750614682859184614871565b16602087019281845211156146a5575090826146a09251169061352d565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906147048261349b565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ab95761477e926040526147d5565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261477e916147d56064836134b7565b6001600160a01b031690614800600080836020829551910182875af16147f96145c3565b9084614920565b908151918215159283614849575b5050506148185750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610ae6576020015190811591821503610644575038808061480e565b9091906000198382098382029182808310920391808303921461490f57670de0b6b3a764000090818310156148d857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061495f575080511561493557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149aa575b614970575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561496856fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615f2090816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a65760403660031901126143a6576001600160a01b0360043516600435036143a6576100566080614951565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180919091526101a0526004356001600160a01b03166101008190526100a690614a61565b61012052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916148c0575b506001600160a01b03610117911680608052614c30565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b3576fffffffffffffffffffffffffffffffff916000916148a1575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357600090614864575b6101e59150614d7d565b61014052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b357600091614835575b5060c0516fffffffffffffffffffffffffffffffff16801561481f576fffffffffffffffffffffffffffffffff61271081930216041661010060800152610287600435614e79565b6101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c88161496e565b519020610405602963ffffffff6103156102ee8261016861ffff8860101c16061661570a565b91601e604660ff61030b8460146050848d60081c1606011661570a565b981606011661570a565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610355815180926020602488019101614909565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610391825180936020602585019101614909565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103cf8351809460206027868601019101614909565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fa565b61043d6fffffffffffffffffffffffffffffffff6040608001511660ff6104366001600160a01b0360805116615091565b16906151fa565b6104516001600160a01b0360805116614a61565b60a051610100516040517fbc2be1be0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b357602491600091614800575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b357610513926000916147d1575b5064ffffffffff8091169116615545565b610120516101805190929161059d602161053a6064610533818706615a17565b950461570a565b6040519481610553879351809260208087019101614909565b82016105688251809360208085019101614909565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fa565b610100608001519260c060800151956101206080015197604051996105c18b614951565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069160c0840151845190615b23565b9061097861015c604051926106a5846149de565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106e86040516106de8161498a565b60008152866159eb565b156147c9576090945b6106fa8661570a565b916040519586938493661e339034b21e9160c91b6020860152610946835195869261072c846027840160208901614909565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b603585840101526107738551809660206042888701019101614909565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087991889160f990910190602001614909565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761091491899161015190910190602001614909565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614909565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fa565b6101008301526101208201526028610100830151604051906109998261498a565b60008252610c3f61015c604051926109b0846149de565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b6109ec82615e9d565b808211156147c15750945b610a0287870161570a565b91604051958693661e339034b21e9160c91b60208601528151610a2c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a6f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfa82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610c2182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101845201826149fa565b610160840152016101808201526028602083015160405190610c608261498a565b60008252610caa61015c60405192610c77846149de565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e384615e1f565b8352016020820152610fe560808301516030604051610cc88161498a565b60008152610f6f61015c60405194610cdf866149de565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1286615e1f565b610d1b82615e9d565b808211156147b95750935b610d326028860161570a565b91604051978893661e339034b21e9160c91b60208601528151610d5c816027880160208601614909565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610d9f825180936020604285019101614909565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9b82518093602060f985019101614909565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2a82518093602061015185019101614909565b01661e17ba32bc3a1f60c91b610151820152610f5182518093602061015885019101614909565b01631e17b39f60e11b6101588201520361013c8101865201846149fa565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615190565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440257610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101008401519160608101519460405161113b816149a6565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119888614951565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614402576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440257611c76611cd79160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261182d615aea565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd260d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161195f60b886602085019361189f81605e840187614909565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611904825180936020609385019101614909565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fa565b611967615aea565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119cd81606b8a0184614909565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a12825180936020608e85019101614909565b019082608e830152611a5660a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fa565b611b9c610108611a64615aea565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af0815180926020607387019101614909565b8201908760738301526076820152875190611b0f826096830188614909565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fa565b611ba4615aea565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614909565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cb882518093602060c485019101614909565b019160c483015260c78201520360b88101875201856149fa565b615190565b92611ce9611ce3614d0b565b896159eb565b97881561479e575b50604051611cfe816149c2565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614402576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145795760405161212c8161498a565b60008152995b1561441857604051806101e081011067ffffffffffffffff6101e083011117614402576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440257613b3f9c612dfa6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ecb9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d968151809260208a8c019101614909565b8701612dab8251809360208a85019101614909565b01612dbf8251809360208985019101614909565b01612dd38251809360208885019101614909565b01612de78251809360208785019101614909565b01918201520360168101865201846149fa565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e3f6026998260208c9451948593019101614909565b8901612e548251809360208c85019101614909565b01612e688251809360208b85019101614909565b01612e7c8251809360208a85019101614909565b01612e908251809360208985019101614909565b01612ea48251809360208885019101614909565b01612eb88251809360208785019101614909565b019182015203600d8101895201876149fa565b61375e604c60e0830151610120840151936134ba6130ed6060604084015193015196612ef78186615d63565b946130e861012b604051612f0a816149de565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f74815180926020603787019101614909565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130b891849161012090910190602001614909565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fa565b615d63565b956132cc61012b604051613100816149de565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316a815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132a782518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fa565b6132d68184615dcb565b926134b561012b6040516132e9816149de565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613353815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261349082518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fa565b615dcb565b9061369961012b6040516134cd816149de565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613537815180926020603787019101614909565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e00000000000000000061010982015261367482518093602061012085019101614909565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fa565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e00000000000000000000000000000000000000000000000000000060408601526136ff815180926020604589019101614909565b8401613715825180936020604585019101614909565b0161372a825180936020604585019101614909565b0161373f825180936020604585019101614909565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fa565b613a3e61019a6101408401516101a08501519061379f61379961379361378d60e060408b01519a01519461570a565b9461570a565b9761570a565b9161570a565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393a815180926020858a019101614909565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a48251809360208b85019101614909565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139e78251809360208985019101614909565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2a8251809360208785019101614909565b01918201520361017a8101855201836149fa565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613aca815180926020607b89019101614909565b8401613ae0825180936020607b85019101614909565b01613af5825180936020607b85019101614909565b01613b0a825180936020607b85019101614909565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fa565b6101605260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b3576000916143bf575b506089613bab613ccd92614a61565b9260c0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf2815180926020604088019101614909565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c57825180936020606385019101614909565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c98825180936020608685019101614909565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fa565b6101a05160a051610120516080519193929091613cf2906001600160a01b0316614a61565b91613cfe60243561570a565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b357600091614369575b50936142dd9661406560e361426c966094966142769a9661417b9a6000146142e157604051613d81816149c2565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400160208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb18160558c0184614909565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3b8260b183018a614909565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7682518093602060c385019101614909565b01613faf7f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614909565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613fed82518093602060d185019101614909565b019260d184015251809360d5840190614909565b019060d582015261401c82518093602060df85019101614909565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140568251809360208785019101614909565b010360c38101855201836149fa565b6101a051906141d661407860243561570a565b916140f7602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140ad815180926020602b87019101614909565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140e88251809360208785019101614909565b0103600d8101865201846149fa565b610160516141049061585b565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614145815180926020602e8d019101614909565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614909565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614909565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d820152614237825180936020609285019101614909565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fa565b60e081905261585b565b6142c9603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142b98151809260208686019101614909565b810103601d8101845201826149fa565b60405191829160208352602083019061492c565b0390f35b6040516142ed8161496e565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e45565b90506020959195813d6020116143ab575b81614387602093836149fa565b810103126143a657519384151585036143a657909490936142dd613d53565b600080fd5b3d915061437a565b6040513d6000823e3d90fd5b90506020813d6020116143fa575b816143da602093836149fa565b810103126143a657516001600160a01b03811681036143a6576089613b9c565b3d91506143cd565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440257610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101008201529961237f565b604051806101c081011067ffffffffffffffff6101c083011117614402576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612132565b6147b29198506147ac614d44565b906159eb565b9638611cf1565b905093610d26565b9050946109f7565b60d0946106f1565b6147f3915060203d6020116147f9575b6147eb81836149fa565b810190614a44565b38610502565b503d6147e1565b614819915060203d6020116147f9576147eb81836149fa565b386104ac565b634e487b7160e01b600052601260045260246000fd5b614857915060203d60201161485d575b61484f81836149fa565b810190614a1c565b3861023f565b503d614845565b506020813d602011614899575b8161487e602093836149fa565b810103126143a6575160058110156143a6576101e5906101db565b3d9150614871565b6148ba915060203d60201161485d5761484f81836149fa565b38610181565b90506020813d602011614901575b816148db602093836149fa565b810103126143a657516001600160a01b03811681036143a6576001600160a01b03610100565b3d91506148ce565b60005b83811061491c5750506000910152565b818101518382015260200161490c565b9060209161494581518092818552858086019101614909565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440257604052565b6080810190811067ffffffffffffffff82111761440257604052565b6020810190811067ffffffffffffffff82111761440257604052565b6060810190811067ffffffffffffffff82111761440257604052565b60c0810190811067ffffffffffffffff82111761440257604052565b6040810190811067ffffffffffffffff82111761440257604052565b90601f8019910116810190811067ffffffffffffffff82111761440257604052565b908160209103126143a657516fffffffffffffffffffffffffffffffff811681036143a65790565b908160209103126143a6575164ffffffffff811681036143a65790565b6001600160a01b03168060405191614a78836149a6565b602a8352602083016040368237835115614b6c5760309053825160019060011015614b6c57607860218501536029905b808211614af1575050614ab9575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614b57577f3031323334353637383961626364656600000000000000000000000000000000901a614b2d84876159da565b5360041c918015614b42576000190190614aa8565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff811161440257601f01601f191660200190565b3d15614bc9573d90614baf82614b82565b91614bbd60405193846149fa565b82523d6000602084013e565b606090565b6020818303126143a65780519067ffffffffffffffff82116143a6570181601f820112156143a6578051614c0181614b82565b92614c0f60405194856149fa565b818452602082840101116143a657614c2d9160208085019101614909565b90565b6000809160405160208101906395d89b4160e01b825260048152614c53816149de565b51915afa614c5f614b9e565b90158015614cff575b614cc55780602080614c7f93518301019101614bce565b601e815111600014614c2d5750604051614c98816149de565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614cd2816149de565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c68565b60405190614d18826149de565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d51826149de565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614e635760048103614d975750614c2d614d44565b60038103614dd95750604051614dac816149de565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e1b5750604051614dee816149de565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e2a57614c2d614d0b565b604051614e36816149de565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa92831561508657600093615063575b50815192614eb6846149de565b60118452614eeb6020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159eb565b15614f295750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614f1f836149de565b600d835282015290565b614f668351614f37816149de565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159eb565b15614fa45750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614f9a836149de565b600e835282015290565b614fe18351614fb2816149de565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159eb565b1561501f5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191615015836149de565b600f835282015290565b61505f9083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492c565b0390fd5b61507f91933d8091833e61507781836149fa565b810190614bce565b9138614ea9565b82513d6000823e3d90fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150c9816149de565b6000928392839251915afa6150dc614b9e565b9080615113575b1561510f5760208180518101031261510b57602001519060ff82168203615108575090565b80fd5b5080fd5b5090565b5060208151146150e3565b6040519061512b826149de565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615164826149de565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151f89294936040519586926020946151b281518092888089019101614909565b84016151c682518093888085019101614909565b016151d982518093878085019101614909565b016151ec82518093868085019101614909565b010380855201836149fa565b565b801561550a57600091806154e5575090505b600190808281101561527657505050615223615157565b614c2d602260405183615240829551809260208086019101614909565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fa565b66038d7ea4c6800011156154885760409081519060a0820182811067ffffffffffffffff821117614402578084526152ad8161498a565b6000815282528251906152bf826149de565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152f9816149de565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615330816149de565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615368816149de565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545c575b508451946153af866149de565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615449575050505061542a615430917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615425866149de565b61570a565b91615a17565b916005851015614b6c57614c2d9460051b015192615190565b81810184015188820185015283016153e0565b9591926103e89081851061547f57508680916064600a870406950493019661539d565b939296506153a2565b505061549261511e565b614c2d6028604051836154af829551809260208086019101614909565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fa565b600a0a9182156154f657500461520c565b80634e487b7160e01b602492526012600452fd5b5050604051615518816149de565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155ad575061555a615157565b614c2d602660405183615577829551809260208086019101614909565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fa565b61270f811161567c576001810361563957614c2d60206156016040516155d2816149de565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570a565b60405193816156198693518092868087019101614909565b820161562d82518093868085019101614909565b010380845201826149fa565b614c2d602061560160405161564d816149de565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570a565b5061568561511e565b614c2d602a604051836156a2829551809260208086019101614909565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fa565b906156e282614b82565b6156ef60405191826149fa565b8281528092615700601f1991614b82565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561584d575b506d04ee2d6d415b85acef81000000008083101561583e575b50662386f26fc100008083101561582f575b506305f5e10080831015615820575b5061271080831015615811575b506064821015615801575b600a809210156157f7575b6001908160216157a2600187016156d8565b95860101905b6157b4575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f2579190826157a8565b6157ad565b9160010191615790565b9190606460029104910191615785565b6004919392049101913861577a565b6008919392049101913861576d565b6010919392049101913861575e565b6020919392049101913861574c565b604093508104915038615733565b8051156159c65760405161586e816149a6565b604081527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040820152815191600292600281018091116159b05760038091047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159b05761590d906002959492951b6156d8565b936020850193839284518501935b84811061595d57505050505060039051068060011461594a5760021461593f575090565b603d90600019015390565b50603d9081600019820153600119015390565b8360049197929394959701918251600190603f9082828260121c16880101518453828282600c1c16880101518385015382828260061c16880101518885015316850101518682015301959392919061591b565b634e487b7160e01b600052601160045260246000fd5b506040516159d38161498a565b6000815290565b908151811015614b6c570160200190565b9081518151908181149384615a01575050505090565b60209293945082012092012014388080806157ad565b80615a2957506040516159d38161498a565b600a811015615a8e57615a3b9061570a565b614c2d602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7e8151809260208686019101614909565b81010360028101845201826149fa565b615a979061570a565b614c2d602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ada8151809260208686019101614909565b81010360018101845201826149fa565b60405190615af7826149de565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d5557615b31615aea565b906127109081039081116159b057614c2d91615b4f6101369261570a565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bdb815180926020605788019101614909565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c6382518093602060a785019101614909565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cc482518093602060d585019101614909565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fa565b50506040516159d38161498a565b60306151f8919392936040519481615d85879351809260208087019101614909565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dbc8251809360208785019101614909565b010360108101855201836149fa565b60256151f8919392936040519481615ded879351809260208087019101614909565b820164010714051160dd1b6020820152615e108251809360208785019101614909565b010360058101855201836149fa565b60009080518015615e9557906000916000915b818310615e4457505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e7787856159da565b511614615e8d575b600d01936001019190615e32565b849350615e7f565b505050600090565b60009080518015615e9557906000916000915b818310615ec25750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ef587856159da565b511614615f0b575b601001936001019190615eb0565b849350615efd56fea164736f6c6343000817000a"; diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 620b5ac3e..7f8e13dc3 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -130,16 +130,6 @@ contract SablierV2LockupDynamic is }); } - /// @inheritdoc ISablierV2LockupDynamic - function streamedAmountOf(uint256 streamId) - public - view - override(SablierV2Lockup, ISablierV2LockupDynamic) - returns (uint128) - { - return super.streamedAmountOf(streamId); - } - /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -186,6 +176,18 @@ contract SablierV2LockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup + /// @dev The streaming function is: + /// + /// $$ + /// f(x) = x^{exp} * csa + \Sigma(esa) + /// $$ + /// + /// Where: + /// + /// - $x$ is the elapsed time divided by the total time in the current segment. + /// - $exp$ is the current segment exponent. + /// - $csa$ is the current segment amount. + /// - $\Sigma(esa)$ is the sum of all elapsed segments' amounts. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the start time is in the future, return zero. uint40 currentTime = uint40(block.timestamp); diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index c0b2c8a49..cf6db6f6f 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -119,15 +119,6 @@ contract SablierV2LockupLinear is }); } - function streamedAmountOf(uint256 streamId) - public - view - override(SablierV2Lockup, ISablierV2LockupLinear) - returns (uint128) - { - return super.streamedAmountOf(streamId); - } - /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -186,6 +177,17 @@ contract SablierV2LockupLinear is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup + /// @dev The streaming function is: + /// + /// $$ + /// f(x) = x * d + c + /// $$ + /// + /// Where: + /// + /// - $x$ is the elapsed time divided by the stream's total duration. + /// - $d$ is the deposited amount. + /// - $c$ is the cliff amount. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the cliff time is in the future, return zero. uint256 cliffTime = uint256(_cliffs[streamId]); diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index 8341bf884..9625b5249 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -125,16 +125,6 @@ contract SablierV2LockupTranched is tranches = _tranches[streamId]; } - /// @inheritdoc ISablierV2LockupTranched - function streamedAmountOf(uint256 streamId) - public - view - override(SablierV2Lockup, ISablierV2LockupTranched) - returns (uint128) - { - return super.streamedAmountOf(streamId); - } - /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -181,9 +171,17 @@ contract SablierV2LockupTranched is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup + /// @dev The streaming function is: + /// + /// $$ + /// f(x) = \Sigma(eta) + /// $$ + /// + /// Where: + /// + /// - $\Sigma(eta)$ is the sum of all elapsed tranches' amounts. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { uint40 currentTime = uint40(block.timestamp); - LockupTranched.Tranche[] memory tranches = _tranches[streamId]; // If the first timestamp in the tranches is in the future, return zero. @@ -200,7 +198,6 @@ contract SablierV2LockupTranched is // Using unchecked arithmetic is safe because the sum of the tranche amounts is equal to the total amount // at this point. uint128 streamedAmount = tranches[0].amount; - uint256 index = 1; unchecked { while (tranches[index].timestamp <= currentTime) { diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 3c43bb470..526813cd0 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -198,7 +198,6 @@ abstract contract SablierV2Lockup is function streamedAmountOf(uint256 streamId) public view - virtual override notNull(streamId) returns (uint128 streamedAmount) diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index b1c465d51..22419db24 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -155,6 +155,12 @@ interface ISablierV2Lockup is /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. /// @dev Reverts if `streamId` references a null stream. + /// + /// Notes: + /// - Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited + /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent + /// to the total amount withdrawn. + /// /// @param streamId The stream id for the query. function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index 39e8216a0..13f69a2c2 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -63,29 +63,6 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @dev This is initialized at construction time and cannot be changed later. function MAX_SEGMENT_COUNT() external view returns (uint256); - /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. - /// - /// When the stream is warm, the streaming function is: - /// - /// $$ - /// f(x) = x^{exp} * csa + \Sigma(esa) - /// $$ - /// - /// Where: - /// - /// - $x$ is the elapsed time divided by the total time in the current segment. - /// - $exp$ is the current segment exponent. - /// - $csa$ is the current segment amount. - /// - $\Sigma(esa)$ is the sum of all elapsed segments' amounts. - /// - /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited - /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent - /// to the total amount withdrawn. - /// - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. - function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index 645ef9f65..63b1a8dc4 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -59,28 +59,6 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param streamId The stream id for the query. function getStream(uint256 streamId) external view returns (LockupLinear.StreamLL memory stream); - /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. - /// - /// When the stream is warm, the streaming function is: - /// - /// $$ - /// f(x) = x * d + c - /// $$ - /// - /// Where: - /// - /// - $x$ is the elapsed time divided by the stream's total duration. - /// - $d$ is the deposited amount. - /// - $c$ is the cliff amount. - /// - /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited - /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent - /// to the total amount withdrawn. - /// - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. - function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 64a7a89bd..526b95ebf 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -63,26 +63,6 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// @dev This is initialized at construction time and cannot be changed later. function MAX_TRANCHE_COUNT() external view returns (uint256); - /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. - /// - /// When the stream is warm, the streaming function is: - /// - /// $$ - /// f(x) = \Sigma(esa) - /// $$ - /// - /// Where: - /// - /// - $\Sigma(esa)$ is the sum of all elapsed tranches' amounts. - /// - /// Upon cancellation of the stream, the amount streamed is calculated as the difference between the deposited - /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent - /// to the total amount withdrawn. - /// - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. - function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ From 63113dc3fbe43438eb305663e0d6b74eefc15857 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 25 Mar 2024 17:07:42 +0200 Subject: [PATCH 074/132] docs: update openzeppelin version installed docs: add "--no-commit" when installing v2-core with forge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e8d7e4bf1..0c091025f 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,13 @@ This installation method is not recommended, but it is available for those who p First, install the submodule using Forge: ```shell -forge install sablier-labs/v2-core +forge install --no-commit sablier-labs/v2-core ``` Second, install the project's dependencies: ```shell -forge install --no-commit OpenZeppelin/openzeppelin-contracts@v4.9.2 PaulRBerg/prb-math@v4 +forge install --no-commit OpenZeppelin/openzeppelin-contracts@v5.0.0 PaulRBerg/prb-math ``` Finally, add these to your `remappings.txt` file: From 458dc3452f925945743802c0330d486f6e8b866d Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 25 Mar 2024 21:03:23 +0000 Subject: [PATCH 075/132] ci: change fuzz runs to 50000 for integration test --- .github/workflows/ci-deep.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index 351e6b66f..928d4a9dc 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -50,7 +50,7 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: ${{ inputs.integrationFuzzRuns || 100000 }} + foundry-fuzz-runs: ${{ inputs.integrationFuzzRuns || 50000 }} foundry-profile: "test-optimized" match-path: "test/integration/**/*.sol" name: "Integration tests" From 0a75661bc77f087620567265e1c7f973b1c504a8 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 25 Mar 2024 21:57:28 +0000 Subject: [PATCH 076/132] ci: change default runs to 50,000 in ci-deep --- .github/workflows/ci-deep.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index 928d4a9dc..16d942d5a 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -10,11 +10,11 @@ on: workflow_dispatch: inputs: unitFuzzRuns: - default: "100000" + default: "50000" description: "Unit: number of fuzz runs." required: false integrationFuzzRuns: - default: "100000" + default: "50000" description: "Integration: number of fuzz runs." required: false invariantRuns: @@ -41,7 +41,7 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: ${{ inputs.unitFuzzRuns || 100000 }} + foundry-fuzz-runs: ${{ inputs.unitFuzzRuns || 50000 }} foundry-profile: "test-optimized" match-path: "test/unit/**/*.sol" name: "Unit tests" From e080f20eafef0fc18049bcc77f1694db043860f1 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 28 Mar 2024 17:43:53 +0000 Subject: [PATCH 077/132] Update forge-std to v1.8.1 (#865) * build: update forge-std to v1.8.1 build: remove @prb/test dep test: rename `timestamp` to `newTimestamp` in `vm.warp` test: declare some functions as `pure` and `view` test: rename `assumeNoPrecompiles` to `assumeNotPrecompile` test: use StdAssertions log events test: define BaseVm contract test: define MAX_UINT256 in Constants * test: Use from forge-std * test(refactor): rename log names in Assertions * build: update prb math peer dep version * chore: address pr feedback * chore: update bun.lockb file * test: use CommonBase for vm * test: deprecate changePrank in favor of resetPrank --------- Co-authored-by: andreivladbrg Co-authored-by: Paul Razvan Berg --- bun.lockb | Bin 306448 -> 308049 bytes package.json | 5 +- remappings.txt | 1 - slither.config.json | 1 - test/Base.t.sol | 6 +- test/fork/Fork.t.sol | 2 +- test/fork/LockupDynamic.t.sol | 8 +-- test/fork/LockupLinear.t.sol | 8 +-- test/fork/LockupTranched.t.sol | 8 +-- test/integration/Integration.t.sol | 4 +- .../createWithTimestamps.t.sol | 6 +- .../lockup-dynamic/get-stream/getStream.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 10 ++-- .../lockup-dynamic/token-uri/tokenURI.t.sol | 7 +-- .../withdrawableAmountOf.t.sol | 6 +- .../createWithTimestamps.t.sol | 2 +- .../lockup-linear/get-stream/getStream.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 5 +- .../lockup-linear/token-uri/tokenURI.t.sol | 7 +-- .../withdrawableAmountOf.t.sol | 2 +- .../createWithTimestamps.t.sol | 6 +- .../get-stream/getStream.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 8 +-- .../lockup-tranched/token-uri/tokenURI.t.sol | 7 +-- .../withdrawableAmountOf.t.sol | 6 +- .../concrete/lockup/burn/burn.t.sol | 20 +++---- .../cancel-multiple/cancelMultiple.t.sol | 14 ++--- .../concrete/lockup/cancel/cancel.t.sol | 12 ++-- .../lockup/get-recipient/getRecipient.t.sol | 6 +- .../getRefundedAmount.t.sol | 12 ++-- .../getWithdrawnAmount.t.sol | 4 +- .../lockup/is-cancelable/isCancelable.t.sol | 2 +- .../concrete/lockup/is-cold/isCold.t.sol | 10 ++-- .../lockup/is-depleted/isDepleted.t.sol | 2 +- .../concrete/lockup/is-stream/isStream.t.sol | 2 +- .../concrete/lockup/is-warm/isWarm.t.sol | 10 ++-- .../refundableAmountOf.t.sol | 16 ++--- .../concrete/lockup/renounce/renounce.t.sol | 12 ++-- .../set-nft-descriptor/setNFTDescriptor.t.sol | 4 +- .../concrete/lockup/status-of/statusOf.t.sol | 10 ++-- .../streamed-amount-of/streamedAmountOf.t.sol | 12 ++-- .../lockup/transfer-from/transferFrom.t.sol | 2 +- .../withdrawMaxAndTransfer.t.sol | 8 +-- .../lockup/withdraw-max/withdrawMax.t.sol | 4 +- .../withdraw-multiple/withdrawMultiple.t.sol | 16 ++--- .../concrete/lockup/withdraw/withdraw.t.sol | 26 ++++----- .../withdrawableAmountOf.t.sol | 12 ++-- .../nft-descriptor/generateAccentColor.t.sol | 2 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 4 +- .../safeAssetDecimals.t.sol | 6 +- .../safe-asset-symbol/safeAssetSymbol.t.sol | 6 +- .../lockup-dynamic/createWithTimestamps.t.sol | 4 +- .../lockup-dynamic/streamedAmountOf.t.sol | 12 ++-- .../fuzz/lockup-dynamic/withdraw.t.sol | 6 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 6 +- .../lockup-linear/createWithTimestamps.t.sol | 2 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 12 ++-- .../lockup-linear/withdrawableAmountOf.t.sol | 8 +-- .../createWithTimestamps.t.sol | 4 +- .../lockup-tranched/streamedAmountOf.t.sol | 10 ++-- .../fuzz/lockup-tranched/withdraw.t.sol | 6 +- .../withdrawableAmountOf.t.sol | 6 +- test/integration/fuzz/lockup/cancel.t.sol | 4 +- .../fuzz/lockup/cancelMultiple.t.sol | 2 +- .../fuzz/lockup/getWithdrawnAmount.t.sol | 4 +- .../fuzz/lockup/refundableAmountOf.t.sol | 2 +- test/integration/fuzz/lockup/withdraw.t.sol | 16 ++--- .../integration/fuzz/lockup/withdrawMax.t.sol | 4 +- .../fuzz/lockup/withdrawMaxAndTransfer.t.sol | 2 +- .../fuzz/lockup/withdrawMultiple.t.sol | 6 +- test/integration/shared/lockup/Lockup.t.sol | 2 +- test/integration/shared/lockup/cancel.t.sol | 4 +- .../shared/lockup/cancelMultiple.t.sol | 6 +- .../shared/lockup/getWithdrawnAmount.t.sol | 2 +- test/integration/shared/lockup/withdraw.t.sol | 4 +- .../shared/lockup/withdrawMax.t.sol | 2 +- .../lockup/withdrawMaxAndTransfer.t.sol | 2 +- .../shared/lockup/withdrawMultiple.t.sol | 10 ++-- test/invariant/Lockup.t.sol | 12 ++-- test/invariant/LockupDynamic.t.sol | 2 +- test/invariant/LockupLinear.t.sol | 4 +- test/invariant/LockupTranched.t.sol | 2 +- test/invariant/handlers/BaseHandler.sol | 9 +-- test/invariant/handlers/LockupHandler.sol | 6 +- .../transfer-admin/transferAdmin.t.sol | 2 +- .../nft-descriptor/abbreviateAmount.t.sol | 16 ++--- .../calculateDurationInDays.t.sol | 12 ++-- .../nft-descriptor/calculatePixelWidth.t.sol | 12 ++-- .../calculateStreamedPercentage.t.sol | 6 +- .../nft-descriptor/generateAttributes.t.sol | 4 +- .../nft-descriptor/generateDescription.t.sol | 6 +- .../nft-descriptor/generateName.t.sol | 4 +- .../concrete/nft-descriptor/generateSVG.t.sol | 6 +- .../concrete/nft-descriptor/hourglass.t.sol | 10 ++-- .../nft-descriptor/stringifyCardType.t.sol | 2 +- .../stringifyFractionalAmount.t.sol | 6 +- .../nft-descriptor/stringifyPercentage.t.sol | 4 +- .../nft-descriptor/stringifyStatus.t.sol | 2 +- test/unit/fuzz/transferAdmin.t.sol | 4 +- test/unit/shared/Adminable.t.sol | 2 +- test/utils/Assertions.sol | 55 +++++++++--------- test/utils/BaseScript.t.sol | 4 +- test/utils/Constants.sol | 5 +- test/utils/Defaults.sol | 2 +- test/utils/Precompiles.t.sol | 8 +-- test/utils/Utils.sol | 20 +++---- 106 files changed, 355 insertions(+), 375 deletions(-) diff --git a/bun.lockb b/bun.lockb index 572d055eee25cc72f6479c713dbdea7a2fafeb60..73c05be7aa4f4fbb3ca8cd9803bdb6e630934b2c 100755 GIT binary patch delta 61274 zcmeFa2Y5|c|2DkONe*WtdPzbMy-W}ZCxjeb^iF~xA|yzW1PMc;3!-giO9-MyiB4qn z(c55*5@ax=x6#Xt^4|B}>v-}!-~8u$zw3Sf-+Nu}HT&|*z3zMUwSH^uwKv)3UMqUx zUeUR=s-Lm8Xt{rJnd7$;Hh#=`)z*5a#`ZEbf1338*p8IB-^_mA^UyYXiI-_!uX3eF zd^BoA|4~?y5@3=H96fJdslby4Ny-Nj6F6{qFd_~J{t&sSrvVE9$Jj|yDPROJKTs9% z!%-FE1A)}v0v&)YO?v+6ifkwsUonp)6@yv`SR5z;3jw2p!$t*1Nz(DWdXwS;hYt^p zj*)hu6>Q@0h(UqTA(E61UJ(4XS+A`dB3WxxklwA!;4D8ZG(0p61pu^&)6mhX_=F}R zL3J<|v;xQieh0FfNx%}o2@nxX7>OT_z#$PaT0!^GC#F9OWd7@d9|Yo0f)Tx8{0Bs$ zs)St-S?+3J5h+MYn2!Kk*cYSE0w!n?QbP42dI2_lSa94Z*7yWE8&U$u5&HxAN&`nA zA1ARdkPRM&Ldn}JiAGD22T025=OBvXdq=roEES&vm1Qjxqq+b{9)$^I>JT6sTOB<{ zbqNK4F2LZZsE8=H;MlTGdip<+j`4fInSKM1bq71^JMmvRNpr+kKzv_Rz)|!H8>7c5LX^>cJN~rePjlO4jxSX8F<0&hzN`tLN47A2?B#6qL}w*a1P-S zfjb1Q5;zUWshC+qlF+CGxu)(0FO@9&a)G12(Wf~kIwC3trM0fCPf!y#y&Ltwiz3%` za8B5HASWK()fUdWT6*m_3*|r?PqhkVNMn(rm zpHp6#%Eh0rr1x}2ecdDCflM710bfAfn=E==#k};=;C37kNd{-nB_Jnu1=6v$I7~=1 z;^W-CI1SSD2Kvaw0l9F3qk{tB62U>kLq~>6QdjA4L%o1SD1ZgpeB8G4Oom<@dZk99 zVK!tfxNL(LhjeUsZ{>ELQgTfnot0M%c}wLhZ`Ii~XQe{k`tc>3iYlAveG83t8!|j% zpmY&Bn=nJ@0nPNb$Ah!zfl+}$!Kk)Ib3I)okn`{ZkYf-S9v2oE6BIHGO`$$OH0c|7 z3*-N2p_Nl3VOVfbP~b30Qd;VR@)pPp4+KsTI9f57OSxC9tY;q_jV&W4DzKKXKGZh1 z7#tct$Zce#R9^JCCi|=mFq>r=Ia#i+G6LnKx7C{+&`x)|jzDcnaBGN+2@UGhUSA50 zfW?r@L&-9ib9xO2;eI%)qh9MIAUiWgd0{RUpMZr;_FiBFVmVZ)sEZgjs9vq17_zv| zIv*@@4~(t{$C0FgfziQkv6AEmy&%$;@2X=-Ag5yB@W5fgD8Lu-T+ZG=Zd^OiD!5yG zf~|Qay6esB4P?bny6FjJp??5p0gsW94Gs<;F)}nNILbChL7{G;;e#Wjppb}Rp@RaW z21djNhogZzdg|rbR{jQX=1&9W!w#5mQ*TLvEkWR*Ft;(Gk{`4K% z8c01G$g{=#Nd4{@ELPeN&`Uv&3yuy)P_k{BwoO!Qj?#B%cz&dt0pv(vo5uzd{Pk|? z7%w6MqxBvXjL}<)146`Tw00#po#+eV3jyB(IUSG)lc97<0hN5C*vAJRJ`^&t!RRv(F0qQXk! z^da2|WCe9b>$n=6t7id_4V)?Boq%k(C-S5G_=EG8HBR|<4Cq-c`fP^MFk6s%O?It2Fo9FRRcDiXArqw9<3DESK2a^5yqpW1@( z*?dSgWS)*0^OUZIYQ@_&?5Xqhaft-7S%V^Cg2T~8oa=(!a3?S!J3VF8LVaTU3Ty>r z`szRzU|}E^@w){&-UMgD?Y3rX$pq!<+(96C5oG9v+d_y-!o zaeXEl6dE2KIwT}U%DYT&NH-wUtp+*(RUp&XQce~w7ay9Yr?RCUfd#;;H*`*8XCSAc zmB6sjuwb`A10@geV$egQqtT$iuqxmz-4V#rqoYG2hoPMNtMu}1n=Fnrn4W>*G(_i@ zh6Kk%21Z9q0jrd#B30t=uhHvsU#sVP0Z#YJFUoI_uE!g}*{gfY^>%)N&Uyo*&K7(MkOjm7S&{9DGjgPUm|vTr>tTq`kND9cp+UGKNmyR7TwtD? z^oHl%tf$LH101+hykDwEgo>j_Oh{D3$RQ#B<(q;3d}CmHQxFx)6O|-2*rGSI7LW}Y z96Dqq9tEUw;GAI`;G+fw$4Diat`da*T$mBz!7-S12~!^$BKTDr#;R5jqzqsm4#&+MsR;sPt=ilpVIyfdII0`w-@6*?Ieqaey zxO=aTkw9*Rfx*$-I;5FGKMO1dy^r9vfyKe!3A_a?#VK2kfFmMCvw64%1_y zLXSWXoe+Nz4dqcN>IX?G0}L7%5ykZ35qNHk36AoI&U9^ooSLZMn5a0!*9K<;ecS4K z(h+@c(DKJ4L4G9Q)Y*pU;UWF(6M9S^YFj~_z@3q9>~VdlLxDxXM}`j$#uJIuOYngs z2M^|ZA=_=O8FY?V`;+?6+fJt{cs#wo5dwvQ9Zu;LbViTMffqTg>uKmY`F?ON(*}s= z_G;U1)}PTE8Z#(#NHAVN4GazEJ{P^rrt6EKZgk}E&=`y?R~a|KF+XDbxeWLHs4r97 z!>{ce{h#M!?L3V1w&SqvoID#9aa)hXZIDwEb3u1XKFDH+lfDP%HqZ~q?YS+GzTkbK znm#AhAkbM{fST7wL=6cHm!wY@^@3hrR8mTojej8MSk%YlX_xc?dI_D`f@34GIHRRe zf!fSVpDv4miHi(&3yqdCuIT&)bham2+ubDTuHf9C+5W*Oh1*SVOyCgm?Rq(O3F|K_ z4NH}czYfktH~*UM35f!2xBW0InutNs(kY}Xf^_>u`6)n7wC(w0w$R4{*`G-Ci~R@( zr(*;L1qDaOL`y&C==I?y9XLF6P({h+LbeGT7&KUG=)mY;?OlrB86}@%*&aJ?>g5ay z4vusS9x;3!ILl7~a*4oGLpfnJ;85hdZ|m(#7q}3}cG>oXC^%xN?Nc207#*V%eLwG5 zUFq8cBdT7165qD?gY+4NE?>?QsWd6=rA#j!yWL#ogvp$_uF8X?3qPFMe%>|2P&oTT zvA)Ors;w>Q*FI0^%Dfd6uZq6P+=|Q1uUf>Nhaq`6k3!@&<`bnCf&d8Jr` zxp4b4JsU+;OH>@I_&Q#jbjY#fk1xiZum8l*@pOr{r_!etx@u~jvwc970kU$UcAfck zrmMGC8k#6`+nZfBqi6K)$f$vCIMRm%y1Tm%a(9=oGfK|th+4+d%K18G`6p0cBr_?u zJuGr1gCx}lvsVIpTMWM{$?jHzvyzRUJr$?ARyo5cNsSPnN4dSv%PfdV39M@|)K;>Q zV4j^M^+WD9IP`K`&~!roFOaz^{oa)Nv>~|&*zn- zhKNIB(Y1VLTi3{%fH6*MnPH5QY_ZB)ptXROS4+>qYoetHbhnuLlPLjpy$#EhWG}1y z5L|Bs`fjpdIe00lUfzZX#lL}7P6cPbB_*xCMZONkv>4(#7K24`YG^fVQvC7rgOc3P zD%ZneY>#+@7C%dI^0pdIEB^TDq9l7;7Um9tHJQ>TERF*EmC_lHABD7lboY zGbm||EOJLM_7t<^ZZS?Tr1Y-qBOig-7NSu}^R&nXu`1a>ZJ5K32It zR&X=KnK?CbEEtDKpTfP0lhtZ^2hB%uiD_hy+d*d~z}?$0Mai~WymzFSaiq~BeJ?Wz z+ohFdehKCSrUq^@*5MFTtAiVUW5%Py@O}x~l6K)F9Tei`E^RN=_SmpkX}5B)j-w$= z@o#69cOeUR0!aykZ{#U2Nqxbvqo6?p!RP^4kGpDPcPwv6SGKmVYB;E5x3{{yMJ$#m zUo>hv<|y}CUbWmou-}*Yx>Gv1fwp8JxXLQ7S=wY7zE_evSPKlQET$iEN_o$3*a<^t z#i^s!P)qUeXq7{%O42vTi~(}D$P2*ORxk|S9WXKUEi9(;)!@}iP91N#GeRwp3Pa31 zV70)oHDi(d0LDCKC9S2!n76vpyR(nnu)02uaBVmeMJQW(} z21Dy^F&_q_+v#&x*di<0-K>T-ic@#1VUptC-74R8)0>LH$5gnY51eZ(CDhViaq3}p z$b!~}8b+@WwoGkgjmFwaN)L3Zwr%Zk_Z+V{^|Z>{pfy1T6j{$=c&Q}!v>K`@*@zi| z)^hzD71!<-c{LcDpI1qn>SadAm$hhv?t%#x9y`iQaq_d8)1h!kzj~p32MV)eBZW&9 zM>pxSD7u+NZV#sCXS1d%{{B|^6f{uqsZyt%k9Re{ZY#gohsgbzvJm zD%riQau;M`cTjR$i)kL1kCNlzEk6{x-s0-@Z1vM=0>O0W;D)mr3{HbQmk{E7XtOBi z#YRe|uh|A*Tn73oRl&G|^|)*>&I`5=IGdYA(%#tS>31Y}m0S#2 z^)1`AwMF&^Lvf-{^T60A+*Yo7nL+SJ++*@!*I^Sd0l4!u1LF|k{(vHF#Vje4UC=DQ$7M?K7Gn+TJ?N-4WVGHPap6sFfkc8T|HEs z23zIQm@B>QTx_kCWN2%kv3yK)2aEiRV7M35x0uRdjvDfACHo`9vC~f(sbFjcYU*r} zbHFeR9FeD9X1EX&>Kko1m_Cb~_1$3Xrip$nzXjv!K#_GUvS)L>5G>6HUS<#$f`ltI z@^wm0Cg@&DKz(nyF+xnFtwz%X1bwu_#sMXJs8u#$Yi3>OmenFR2NQK+CtRT<53|bl za40=L>-YW2*wP;bvsco3TI8awZGGa}?x|!Cw;B=^r!cEwui_tOmER(sLzq_y^z<@g zPvMflhT2CXjM1lL8=^RD+Sr&Lfa&YH3N|~oRU2H>ATTd&buB@N>9u2q`6n>?`PbdT zXx~=37U3iJ!U%J5XkKpEruau%{2yXj{k{jNGd zNshJ3DbSEew9>UZUbN}0#6}SehV2${m^yh07rRfS&Dgklca^W6&9q^Ry7E>26 zEZauj@=S#E#mz&|VK9z{c4ROadUAqzkFX%bRNA7KBf#o{>8tbrnC_bxS;HqKd#u&u zg#&|LeiTAn`pDVD%M3!#M@Mluc&223Yc*E)Q=G^7$OHWJ_Gu3tavB(W2o`6NuYF~= zds+;G6sPf4S@qXPP|`M~vtZmsum%3+Wrho~$~;QoJ&kyRARSiiJVbGHkPfT%%)ha` zeQ@IW8rS3B*a9$)v7YZVnBF>;V&7MiAkbYg+b#P^QnV5!ajYz2(gaVUjR*OjRb>b}Yvo$J&=cO(XyGAfnl3-_crDXQLat( zF_sTeoTvH7-9zvu9jWx5WP@>-u?3=KtwU}1W^Tp{!QcU+Z_mK!3~*vROmrHmI4Am; z77V3FV(l4zRFV^|roF>(Hdj&;y-kMUcz3FWS|HR$3nhIGT}G&>rj-hlq;`tStVZ?- zXvyRa2=EdoCHR04*Bs76=&(Cn1UC_Mk;l|nFs?w{La^r7gK_&TqPW5zbHKQpl+X?_Wux?z z`qOx4Fisx!3aq5rivJud$79Z4KGInDNMj%U^^vCVCAlyd%a(B2!@QJvb*gG_h2ju{ zWr~sm=itm9W83;&{k_Z}T!Q*WyalY8mJnOD`6XB@F#WzV_q1$=Cv%_H?r08CU>slr z>MCV>+$}IT7BeAKW%(Wb-g6KlOTtE82hXT+%C*iurWROcb(DZMjqDLKgs?~aE0uf^%Gb8a4Y0zyYBlgiwI56$0QkA-JsC?e)g6!Jq_t=a zLiBI62#2I2U|-YApTT@=WtkeqqkT$hb8pjhgjy;A4ZY>F2w}(8$4Rc3U}Jn)0>bWS zLnt2wW3$2fV@4;~D&-w(7?@rS56bJn#Gv%Im<$uq9VNiu+tdxAR@$8}86mvx!qUHh zkgf4v=1KY{j$0}Y?OnjSYZc;EqPz=?32_usz08yKgDcvCyX_#bW{AQ9$K7EK7!Ge7 zj&>ILF<2vwVK7Zqr*IN@#~q6hcOy7qXWZw&nrNwb_qLm=PlvX(nA(6f(}r9{sEIaw zR}j+f+@@mFv=VzXG9#dmBX7I=z*=bqVt7nNrt_B1GfNMIIHX#&<}@(Q^jCk8UkOD& zBehJ_8>ul<5?DX2@sAPG2bj%mKEt-$xxcNOp*S!1kdDwCv*2i)8b zA**&qP!X!7CFe=vAy|Ddy<_EO>q`yuH_6KkQdf(Dhno|@T7dm)OwK~#5b|zZn5rW}niHENPVC}V9IT`uq>w|<%q_f57Jzq&#>mx6N z$olZErIkfK4aWYWKg}%0PxF=D={_be1-DiuwWYTl%@Cq7HhA5-Nl~2F`56CDl-}!n z9BMDn&mDFW{>lvxiTZnv!3&gY>wHX07Q!o(oORx&*Iz^JzvKQxZ3#l~9)$itsHYa{ ztZJe4jqDM?x?m(iUA0jAMcga`Ha4A+Q9 z=B0WJdsyR{mnqKMe9YS*Hbats z`S5EfED-A+heEIA$fTWcVwWq<+kK2{mMgut`^fQWwt?eqd@~rUMMd>3^6!Gd1>r-r zSLhyvqd!8Yf$1aby4_;TS)n-Z^f5ZGRC@39k-Mza?_T=bhh<=1S`EDS zUIA+c_ODhut+EXRU2(@MC1sb7{0gF&Puy5NRx8e#K63c#TqVhCz~}&ycI3DW#&JeJ zqAcbDYjhv_T8pVIlm?2+cyHsRHA>2EA9*_jE=a5ZzKC9kWk1O8uTu zVf$C-OthH%!1U+T`3SLvSZ>(0K=jv_MR$Dd2IkNgj9t{WYB>RnEyts6oR=BI9VDMN z^c8k~^%(e1PcS-yK8CZv*iN0D0@J6M_ZH(WTXo!(yuj)rrM8L4L&4gD;T_TqFMANY zjx%$2Tk}6jNQY*AD;P>NU4pvvG8ui`IL{b^KPX#VEt|- z<&=;4?ruH%*JUfaWZ6bLZJ5Q_D@*Bp+DD!Rkxj&iL|9B`z*=Z;bP9j3C)V2H&=!nG z4ha`t=<2WQWqFU@S?!QwwC+)^o$+y*1~EU9&Ic9*E(cZvo&Z)6f3?z8HtbQHd-@o? z_9-bdtoHl(;N^1OYS16!^6uxeRKUzeW&}KuR~u>53@|;xS%mO+8+ZsSZ~z)o;E1!= z%N|63)SLS?bOE8(+LN2(K|b}l^z=3c9#m4!`>reC7kuR3e$bbq_7{(GvBSBirX5%(v;ngWCr<%urMR^9mTw{C0bSc@jE#;c zy)XL6sYi5Yh7;iE`x_X?6-y3tT=S@2iOeS;Qy(z=JtEq>@2HaUvybulQRUjtK61=4 z-AgcI*cG>diAvg89PWYzusqBYZjAM``@L!MaoZxq{x$34Q)B$M|cVCSZ)y z9j5S8*$jcBkC%EKE#`wF@xT1(EtFP>$JW`Y4_LAD}*eXR^z;OQ_X2)j{pwjH@xK)2yw%}ITyFpC+C%vUwq{87i@!uJ=1vX zg5rGB$NUK*YyCPorp7;MXF$9Wnukzl#Gxmc<=bGKw67`Usu%SWhQ5D~1mh@RPi$o| zZojDA%JcqgtCNG#9E?dYiP+;Nfa!yX?cbR7vvTdWkLfYQZ?rwF)FnNuK33hpIwC7h zK{z381@qMkLd)b2V0y9Wn1kiAerU6YI~7CAHBXk!SM(JEm&3u%3ye9mL!WWf6~+0E zkGxxmSale*w^x)Dh?cAR=8n1Dg&Pf+K1X~MP6w-_mBKb%1*5;hL2whymu-u4#gkgY zY`&9_V1IM%5UIp{3STNwM?uB^b^S`Y)|L$Wt0TKTu z<#%sWo?mUD76{=n{&#PO=?Kx)>?Qn#zwHKQJpZfG`+0q3c^&(BnGrBvxv>~{8BP6n zG(mHP8DJGeJdxX9Wx;bJ^=d*VGGBFpHSo_OwI~F>B3oJu#)P#s_3x4CFcn&QoMW`> zuaN05?h?z#Y-s5%te=86jMv{G3upvmkE}2wtSO8ak@3w)aOKAQ;2mI$hf`|TSL_bT zg0N9(*WV!v=pxb)^TPZD&y5Bp>18Qp$xAb=ymIEHV>~Bq0E{IB!gvwM2MP=V^2&{D zS+J)5JF>i?LML(v!v)WcEI&efUe*IzS4W71L}nZ*IFVx;3uDGO7_Zz&eGJT?p3QHF zR~o%G=eGFLh*}QAo*-c-)-GZZ*j=6eccMP)tcdNr2jc)ffbq(W)E{Z8j!gfUTy=54 zFQPO087Z#Z$OZaNQ*~sv_k#Z&a=t#nnEo>?56qrKAcH3SV7++_lD-@f&@z|>%1njp z-%!nQFqDetG!_)mLhXFE4y!Fj@U?~CmPhJ1r4RzP_YU*H&SYXA8dCs5uY2Ww-7qfpmcawiq0vu7OI9y zz`IgTW~iNoN@TDLf2gU24CR!)?;O=Tg$#~eph&%-vuuCH{|8dyFOu^jvP%I12MC?W zU?6{}jSCy9#xq&4h$b>PSl|#Ks|%$lkinrMewfgSOcw^^$j6BIks_YR_|Za-6*@3p z%MdSw+{lJa6d5Or_}o|s@ruxiO#hwWMEc@lAS+H4xD3d2D}Y=Z>4t84!VD3yMI_uN z_)Z}HNV^1P0-13ikOd!LNb9GuX!ZW@zPi!BmlW6rwKj_$czhtY~W%MzXHgLR|0tvnQy(|L^hQFUY_YT z3H`5-{wHll0#>k7WY{GzQ)DEvpxuHKYk}VbvL}y4{1XvRWcsHf{-w}~)L#isG@*X! zJpydNXOZBGKz4&YvBM8$v?mcrA25Tn0S+R*puj=`3j2Ame)py|>W&2_7io2MQi6FvJe~D#Fq*A%p|Dj79-jQ7n){ zH6F;3nFQqZSI7oTM!Z28_ob9}znU&m6B(Nbq)X2iToJec$m_3=`4%Fctx-ifBK1Xr z6B%5LA553Zapi@;S7gL8kswXzxshuqUBs^!@qdM^c!P-lE97>!%TBK!0WeMYU&oRt z;ta~;JX`>Bp0Y*xM0W7H;MY0+6mo#{klTX)CK3=CyoVp`5r18V_(1578Hwxv3vy~- zBOmKCy+^>PhB@Kr!qZ_viUL_rA#k>@h|vEEnXaga|2t$;OCTNVFAHS8av~ovUaQDe z2t+2RAUKh{qQFW(MpeTP7F?6$zd&}tO~ezKz7CM(xeMLhUbw=)1jPPZg8wIH!5*R@ zPau2NSQJQP1wMlR9WtHO9tn+VhtlGl+)CslGQPFoe}xW+?=IqrOy7fC%|LN%mE@<< zeWk?_H9(}!jm*^#I(sz$NFFHC{%9& z<9rOri%9(hkQJN;764umdbZGS0J$~)3gilV%cnkOd=KPBR< z{b(Q?GzQ3W#{;!jXL>*vIAl{1!HmwgNl z&*VgyuI z{|d4JH&6~M`bCuY7pU*Exg$7~cSVN3LKb`v@myXnMLHrYdM!AS>D~yQ8>zn)`dc1l z3q#0*MahaCxHtteVL`!(v2o{IVhLjZXL{5#9;6$e5#hqBz`>zw5`2W*e zV^$}{*U$jJ)C^?H_>jP!{`bE%*6NG@+qcDNhZfHU{cnG3j53YVOM>ga5u1IjfKzo3#%1_GQ~w>QKN32T>Hm3a ztPKd?DswnW;0K4P6v=-ePc1c}bFaWl;-QRZ;Qtl5Wd81LF$-Wkx66Ot8vpawI79ft zKW~k>GPJkIT$BI2HRju6p40z%Yy8h!h`QpC)a((q!Je0V{@hE>P-U zaSR@}=KUhI*OkE2cg_|J>UHB|(1x|o?L&Gv#TGsP{ekqe>vko6$sFlvD4Z|;^s)@M z0t;U*vW!2mdfBE!-M7541{|4`7O>ZdC7n61_A?dUtyvY`g3)eO$h2^63R*zklqt>tXL=1;5m7CGRM4ylm8I zx0S!SZcVlO=>FZclY5eBFjOa|)(gX1HG+Zh7*4Yu40{Kdo3Z zf5^@3w_WF3BUcXg{=5q9u{FB-@AF_-^%^-AW1|djIZU(`(IfPFXg4H(7A-t!M(Hz1M^#g_U z77zkjKnPXWwSeH)5`sfZLp%N-0beishVJeB2fiwBbX>-Tz%_q7kO#%CNOY@TD1PZ1 zKi`7U*U!}IxzO^^H@i}?XRnV-7ri{UY_!$s=TBdLSgC$$X>e5cpJ>-xb3O^)~bGRs&>uD`a-ul|$E z&Z+8`pnUO)_!zvk>y&mCquin@Ubq^%W`gJYN|D?5Rz8y%(ArSm(4_a6p5OhJ_vrnu z**Wii552ax<1n|jedkWDIy=!Ad~1C3MenNp9D1w3ABA4DpAcGOljqI_Y0tY{>eDfB zaFz25ng!)gQ1|&7BAe9Mo^#`6iuwCLpC4O2@f&%GLstEWyv8AsmbgV-rVc3mvBH@d zjfVZeKR(#zzO@ZnPF`VbM2e>RGIEKqtM=G>lber zd1c0fRR>ch`Ye(HcF(!E%IvVFQoW-~{nD4TcimDr@m1ATx6>Ej-`})i^eRK~FYj7z zOo+|jC$n)!LxRz|w`8YV+0oxV?3ZDGKWvlpx|9NwJ6(G{%G<>`-Rte-4ta|ym|$#jC}>Rf#9~EOuJhgW?X6b5 zDz82Mvtgb0ksb+c`p>_6z5Sze{imJy_Q~Yc5kG9J81P*6+nBH5zO@(H->$m<@cuuR zuP>gtubaWkxrzK>{Igkc>zC7=_bfkUNx3!6eNTVc z+u(%fu#vUePW2f2VVjzNroY{?Uz}oQdlaacSufmBzCe>FzSpCIt6bUMx#Y7#Df0Sj ziGFphRS%wgIO0mv6VrzZkXTGIB-(?6{o!G#JeUX{r>Cm z%!OkNA^DoD=+vZ-x$lITQ%jHPKdr{{KO0s45c*+vr__UP4!u6DZ`M9GM(Pvs_Qksm zm-ig*I_Fl0*`6zx&Pi-JIcVY2pkAFS{gT;uis8JW$(N1R{9&CIclHill(ArThnb%e zA9U$#Ik7X}$9Hoh4N{)x@5X+q-{;iGZtKr&nb^nrZpN3BYr1zW-0It$sDhS$AqUhB z)8OR})8OSbRsU)5a`SX}`92D6syv-;Pa$kNgxYErg^)xDE{PD_)zCx;jx!*frQo4D z&46%%!nhd_>ZvCw#Lk4^HWPwHjhhLf+AIh;6dI`2XF<41A!!x_Z#A33^dtz4lOQx! z6O$l#&4%!lf>muW8^Qw$sk0$8RUbkyG*g?-0W?>W0jlp@M1Put=$2}mxzJmwX@u75 z2ZFEKWgei7x{lCRHOvRJQ~e3;)vbgMs;r=(-3kf{Q&3PRHH$*X0thY(Aaqef7eH`a z2;nS+ZmQEl2q!3vTL__tdXhrycM#mZgV0Nzmy93PR0wa9A^59t-$A%aA%`ijovIL~ zFM^PyLcn%P!7CX;<3$j#oi2j#fWlJ>focO5x+n!ghZG3dPE#QGE{5=l0=Cn|5Z+VB zSPTK%DTVYU5CWD!z;?O>f?p~Ghg1l|RR2^6=A{t!QNTX96vA!_VM`%Is96+3mO*e? z24RF6x(tHjatLQBM5|8AA)KHvZaIXJ>PZT*X%KphfiPNiO@mNvg`uE2HOOAWUBg;Vy-7s{2X^UaKH1TnQnbzn_QkfDm6+-e~t?*?j*49*3q3 zul%KI?^WH$eY1MREon>AkmCnmmF@NZP{6V;Mr%mTJ9ne{)qDQ1WVc4Oe>xU0ud`>t z{uSHnzel3qhbQppAufBlPtJobw=SigYdE*vk!O=1H~gGYVRG}I{>YejFm(1^xA$$g z4lZtAY?D*nvt{2V?Orh>=t2DQxWej%iR0VPKU8zbw3BMmYAm%kt8o9Al)K=cigtff ze$M_NkMgDbORnq`F!=jX>0|vbypEjM`1Gx9?M@y0CF=e2Qk63{w_cRqqes)1je}a> zo&BPaWO$l+t8Ihg?rP&TD0lU0lshGNx$a9VG+z-}=2qvV^dWQdOuV$%*FJvN3dd`U z>lFND>a-D~YOVc#>#TrfGs{f-Q1H$EDbr#fny+oXxa7O^k87_CnA$T!eadn_vD|67 z%YEF=((jXUE!8)F^)gS-P4e_OUEt)t%*pQNyT#9MZgZ@{Zyu35&y@4)adGUfM#D<{ z;$v*}t$gXtiZ|tlO?vxhul--t)U`N|qyXC*nc_QX5gspwQBpF zNT1$3s#4~hjl~X}*tqcZlf;u%57wCJ`k`c{3jLxhRrG)LSx!CmFb30NJC7u)AJ$;@ z{nFtM0c+t7Gu3r#A(+=ea7c%cr23~r*iB&{g*mFc4noL!2x05c!+E)TxW>NkuSH`& z9}e=XH2<}{wq25Y&i3{W4XTzke(18&(EdzfYNwc@rnF0CKG&(;ujDhs?wda!T6C(} zJ?rI9k3F`Y8Lv8Qz{t6*M@5Pnx*ips*no=8Qdp=uZGaHF5yH3)5LERfg=!fP+%`f; zR^v88xJn_1!eX_0288LGAS7i#NL8~bcx{HzcoSN`EO+ZaK51@QnPKeMHqX4p*N=R5 zQR{o$vfK4~M89n_!rHrS+3m8@vDB5=sMDFN9&YWTE=$RCcH59TG0_QYn?85zRio!; zHD@zg{}kmK($of(agq7+;3cgzn4(+?dOuL>jvCVh&cK(@JI%a9q{!NZs zrgVShS|RPX@1zAg$}gE%%`f_6+wE6^+&zjn*tha>aM!p__T5(YjDA12ddI2bbIsst zHF*n)eUD<*Pg~HTwYfXAcHgtw3!9axxXbk2nE89_H0f|BzlXQyx)s}x9Qabi`0#bL z)DwNa4=-z7SL9aRBT0siIibJZ=#&2ZqUYQ@D|=k{Em%$628Wy9<(c`$K=)+@zB{~P z@}f3{i#C~lbZECxqn5P1JTCOadXJcdrd?kz8(*<#`q|)&CPT`nW%TT_4cX*VLOI9 zL-pT|igxcnMf)ghR^=TKLUuw3+W}##nnl5J7X+7`5VotKJ0YB)a27%b{?duBYew-6UN}D6(|!8^_r%Znt_K`}x`L z5Bl7F+_(SAa=ZRNNR#})>=J}iT;oCM8^d5ZPdS`J^9oN=vTh>Sz|682j=~I`( z)_tm6Q(dCwd~a}!zqRyvi@EQl!XBH?6ncN(9JPMes2=&&CR`fdcl;lv8%+DI?a52C zDsDdf>3OxxCuxryGRl@K_f7ZTJ?|~Fj2~P7^@awyI&>&^>wfYJd-8a>-ICGM=l|&E z*R$s5ev^L-Sd-=HTKQ3T|1X}s5AV5OEBZu&Q-R*cn)@_OExPBMot7%0r31d{y)OPh z@+h~?YSJD|K;tZo!(lZs3*+Fs7vu1h!cn!s_YmGwNc|qdarGgE^nDOI?16AnP2K~+ zZ$E@j6i%yc_ChcpfRM2l!ddkLh20ba_CYwOuGxI+-Gt0yT;KLWw+2M9T8 z+z$}EjzY+xa8s>*7{UVzNrxfaRP$!~Y7jE)a5r;L1?RyfMTdG!t7H9c3> z-TJ6c{tIQ@o3E>#H|jy#3g5YHebBK|{JrjZldbO;f4IA@)3>?i{)w7)9JM@EKM++7pgzurMi{yN|jFmUaNtGH)fTg!`4N6}_B4j+gX(k!<978&jN7;~5dKt8QkZ@Yg4t^Ol~2NaTiG_*4sjOw)?4L#LG7oapg2gS~)&Nv6f_a`V%shEsv!}CzyQ%OCK zV)CjF&!d?1ix4_ofFP^M7a;ik4B-=n{A!z@Aeb*f$oL6@gZhEOZVCYxArw;AU4#&F z8G^&l5Q?b&KSOZ50%0G8Vyb)z!U+mtmmri-vna$~h2U}-LMb)$GK6Z`5YAF?Qk||q zxJqH%6$qu(lN6?3gWz@*f{Pk=6@u4w2ssqWsnxR~JfM)24Z&5-rm*M+gvQq(R8$kM zLGaCi@RUMjwZU}=?bDXwbgaMKnS@F!QmzZch&zU1jkUSVKppbM2 zLQ^%H!lL^S8sCM`Tur1U!V$NnQ64LdX*c4v!#oQT-o5aC{13ABAqJ{20Os z3So~S^iZ=X#6E-I@&rOJHS`I7RQnymSqlED(^CjnDU5pxp^ti!!u015+@3)QP~)CK z@Ol9uheCg~`tJ}PP)Pb6LZF&WVbMznjh{mZQWKv;@O=g0DTQFQ!3zlQDWtxDFhqSw zA^kOk4lf~us>v@Q_`QMfiNY|o%_|7zw-7R3K?qYnP}of&;5CE@b=_+SA@3kKyn!%6 z^?w7w@x7sdy7!HteFy#ypzX3h@V51ixj)~`p0u`nNC|)Y4#(qnUm1}xXxOAtr&j&C zy>I7+dHzUWbG@OoV^+6szn@XxJ;GtapLUNcd~P_#{#E73nNI4y_t&w3M2&C8Q? zgIT>wdE9$cKUO{Y9_gn43Bm0HgmG%z2MAstA>>eqSF8U4;Q@uDKOjs{vnee41flVt z5GJXKe?sv64B;t-DQbg{5Z+Tr{Rm;2`jA5U7YH3bK}b}SKN)&0^fO|H$Y-i;J|ltI z03qWuge3I?h20bazCf6xuKNNZ#AtL_=wNJTn77d1i21Pt-3O|uvH|=AxEf}Fuu#pS z5Ni*?#Rx%FLyZusnIN2{kgPh{LAXj`oSm^<2mY3(?Xus#y{*F{_nYIFtbJq`*RE;y zl8Z0vC9eJRt=q6g>aXW_94hGWbXSW2->Qihrq?O9_R+)33vPZ}rSIa|h4&P!czp1q z`s%nmMn~1n9u=jkarUUlD=#X_p|DJ?Zi4WDLXrtWnwm{vkr_hcJZOsT7ev_{`_S11 z0^fz#w{C3d@@Kc5F9OTe88hU1wa=@Mckmb+RR8;X_n!?8*>!iAe}eP4?M3@#ws5cX zpxFH8Q}^xNoA0NF6K}Lt8_Q_QQ&YZKk)sA^_6ZdDXy>aY9YxOD1P0foA ztW_W8MF-OJ86DbpEaGR~5?a^hM7q3&3%_!C{KgQ*g8TD*X+sF{i z1t4U|=n#KX)^^$N+UY-i_Pja|3;wo$`!|CpRP^>}aG}$Z@@knE`{s|Uo8=aMZeu{N zVmE`&kKX6I{OyuX#XTCE3YS0kwzzBedY}JX(N)bTfDQ%ZLq(g_b@@YpEiV?hY}C~Q~d0uWA62rGc5@ON-+m%T^i;5=pImWzuXkFPwWT8sOU8%JLCP#26n zGO&ZPW#P!n%^y^)a`51^=gamOQ%+@>*VWmZR>zb@1C#Os=RzY z`p@%fY6>IH#^F0U^W@ zfPW3MKzWJ;l?^k-h=ujE^ZZ5A}Gn@bTW9Nn!f=8`7_-<0= z=T~G1 z6k?qrxHv+%qJ}y`s8$-nSqj;zlM{ri6vjD0xUQb0Fue=}H)jYrYMe6!FBb?o6mF{3 zOG9`-A*nQk+iEt2MP(s0E(75=HL(l?-*OP1Qn;%&aDniiLaGad`|3jq>E$7GC=21C znp_rwpDRYB+rGXh>#zCVrCE#f%T^6;xGQO|TKeq47rULGd@160D?V!QkDqEUXgG4{ z&!6II1r+pfEPKDY%g(jiS3Hl8YA>>f_q*kv2!K)gCq$&`;sM!=AP-tA$h|{>8I-{zw zr_pGq{tE1E$A4ljF8ia^m!7S;uJ)6CJ)34%8t}mEJa~yqdcxV!BaSU{7@FAOb>_%D z)8?C>9dz%WoYs4H;l*iodGfx_>bkn}^;)t0Z#G?oa%@gxZ>P?$X6&desMAEo{|_31 z|5s9SRwq<97BgMM!%Cq{{3m+x27K7gUM*A8Xf{p7KZ$qXM-Ast%iLSjxW#Drlo?jb zc+t*KMr~Rb8Ph7@mxu6e{!(gWUE@K+XVu-qc-&q_ZAN4(QL0)y*dt+nmpCo?%qF)?y zo-p77n%OwLkh!K%z_nDQp`NHI_}zD*;oo&hGlaHWX#5v0i-ndZH2#{|GVxn|5(DDmy9W*wMzlWN@f^lsW>G<1tnPOdK z7}0-*`MZSQ3vr9c48M`a2yMH_%-^hq^J&)(q4Br!RtU}ZkqiDqo|Qu52QTo4|D~+7 zT4?;p1xL9U$A7I5vqVDv;!3*E_6V&6_&TBO6PfuN`|E|aUudPkHwf*3&>X=x3hkiK zILcTw`fpVp5+dAP+94ADAT)ksYbT8Jbr>4{XdjB(1LSp7q;o-ducqL4j72*BUh+X0 z^PUjt${~CV#_OaJ^>g0J!%o9^T|`2Tx-0A~1zeX!<_ZXxfzeN{2(2Q*U&Op$6dVqw<>RnbTyzC zWp{Di5?W1!`ywwL?>00Rja^ad#{lP_Upm1be#}z}q=@T*$XpBIAfY{k#!m4U9tR7J zUqNBsIFBiOh1L~e z{_;DVHePat$a3(h7_BGt+A1PpcZAs!YE^~S17UvFfu3AVXgv`gNDswTU1+@!4iQ=n zq4_}z6|zz6=3Se;w*A zv_a7RWFfd32`w1mI2cz(d}ARF2H}U^c=3Zm3=VWiUT1TOg^IIkKCw^6l>0)6$q0x6bbN(r^XC4rFbrISago_J}pJHOV zv9N~-)1kTn8T~DcpS}wM_7dsFA^Zu(>GBiWc!b$&PM1G4x=%beptfSD`-p@I&{_$t zuh1qy<5yES8UaF^h%g(@k>IzW*uY5)BOQC*UucsNc413#4G`KCgt24B^S=#~0);pg zVHU=g@?%mga2kw-Q412VEnWT(+?KfLEbEI_2srI zsr!rAl~o<>?aDi_Ma;|!6V;aXcK8oG)p7QArHjZ=^1<@M3cw1g>+J0+#ycYD1al_l z0m4edf-tayV8Jkc8^jOBf9K9qY#x{lq*aZ5qNWU@Kv(V5?zkU~6HiuteBQ*eqBQ zY&L8TY#yu?#*q7VEW&Xxo`%Q5zJ+ZvqSZf3>W?P73N?N~qMNW=FuoUD1><`>p5b|B z=NX-6^5v51oX4(f{4S)+gk{0LhwXvwh3$jwhaG?&g8cwH3_A)t20IQr0Xqph4Lbun z3;Pjv9!7td2%7|(3=4)0fpHaZ`{t4h;7za}0{vlJm%O>S!dzfwVec_5f5JY(KAF^O zvYm6hJ*L$Jn}kjzqT@4Qb74GWE`%+DrN9=$mcUYB%V5i4D`2fLl01C!tjQ1FxWahG ztOVl+aa>?!VLVS3f$hH!US4;ase^H`>+Qvehi=_>?Vxg$h-`@3cC*D=FIPC{s=n< zI}f`6`w7NZ9zVlQ!w$oE2;`w}Ff0f*2xiBvir-W11LJpB9bx5Qm0*=&Rbe$?`C$2B z1z-*^em?gZDt`fc33~;51A79i1>=U!4V?E&-XD28LBS928vUSl@3 zkHEl1%rF_250)Qx6mh3uJUQ~D=nZQGYYgM}l&ZsO!uXY$`>=gw3$`1U1=|DL2Ri^e2;*t+2iRfQ5!f-`cs$Xyg|&mVhjoN?g7L7{ z4dxE33;P4E`6uin>@(~O%mAG`nH|g?W`gB~nPCNBuaV{*>;m`OiwN*=#>3bZ*i~3{ zOvz&45?DXXb$^(GFdweoz}~{%!D>SL2IdCi(|;E1d)QtWAL#i2&u4BvV;_O>8Je%N z`P_U8cG{>u%Wqe=Wj4ZmeC6SfPp5nu{RPG+&|5G*Vg3sH4R!~17j_SAybl|RwvB>K zR^1EO6^oyNU=oaH#`&-|Na_vaudDOS_z30)>kjJ*>jL8uF$DGv%neoxRt(0^K>vX% zKEmF?cvt7?jHj`1*g#k_SaVnlSWC?RfdY0e@!lZyVUtk65>&htmImXIum!9c%nD0K z{Ce01*hW}7G=3)P73>Bq2X+~@7{(81#liT&tvZ;*A~1fiZ3L`0j0df6U`6@$zG4XQ zl=U7H^8vTwx{{j}iP1@b@r&C%6YJ4~%C`9wYr>U0~f{ ze2(b>>j~=!+zOU~g82EbaWGFbu0G5H^MW;iHG)-!Re@E7 zm4KCkIl`P_WnesU@gZ1-<%8`+nLS}cVLZ!PVa>R(n!{Sas>Ar%zLqeam{iyzSegG( z+IN6ebv$o#@3|<74W-Ie5la-L7r_G9OAsMy#11G}k)i^kQeqb?mJu7EVnY-oiWLxh z*Jv<`H8ED~rf4kxcTN#h_$A--`8=wrT0ufLzzR?*GKCh50NzLNRG0uH0@DHBL_Y;y1KR-JKpz0|fHgoGz#HCh zK;g%G*e?95e!TbOy`~?)`$iq03ZM^E2mXYrE(4*EdMtpi19T#Q?$AbKfWNbP1H1yB z0_+6G04MN#4B&D~84aF!N7n)1pTc>A`o$yPPLNC~I2X_BWZXo^yQwR{dO58;4Jc(< zi{l_PL15lADXkrZXMdm%z?+}m0PkbsZ{WY1z%Af5Pz+oJ+5)_(`4fl*Q~vSsj=+07 z^Crd@Xa#%=p}GJ}qX^9n;5ZAzdlp4F-k0VX(a%Q@|fKlp6`DH*neXG=qF^D0!Q$i0K@}vz!YFIz&;ggY9gLl zbG$VSMi>MH0=yjZn!#>UPk<*MUPpWZAD}PL17L%6RW(At;K3Pi0)7ND2ZX%Pur{m_ zTIC)x6zZrAxRu9&6F@g$c<%4Ug0)(g$8}{=nZQ@H$KyWE0@%>2Ahbnj0~F$!;|xc{ zc^YYl& z3vnkZ9XJrricstq^Bg+};Knd5`$Ej4Y^N*q%#-P)Ixr0dAi@Hal}xFK(|O>3091G$ z1`Gwl05)x2(%38Esg4%{_EJUz?7=H}oTkw7vkt%^V-%Y3eclNCPIUFu4fWZ zfHvg=c>tUHK_C|C{9GB}p)dvUL|`G10n7wu0MmgVfT_SVfYS~Gg}_pP=??(~Kt8Y- zkjusE2h0JOc`mRUSODw-a)2$sPGAL)2K)%@05$;GKo*b* zYzEjh+z6}()&XnzR6QLJsQ>}907c^YcxEAH11taw$5L|(%L>K9C@tbVrdtFo0Tg;p zQyRpy92d*5IdR4^fYr1H;L4T*tASO(N`PCJ0&pG+#9(?3xePxm0<&0Y7s;bN_N{xI0*_Wz&^swgskB%5%5yvmz+Bn1$aer!!yFgQF=tD5~0y zXRbtH$_11PIZY9YnX!;;6MF!qQcmZ-XXa(o6n-ou*TG$O5J=(vX9>9=hs;nZ$Ocx? z^I`(B)9{Uq>0QM=y z0ccb_I~1S%iAW@l1@wWxk$wSSzajzQ9E33lt0J!opa)b2-XKkbPzRxa@B_m4z(2ro zB)>)Y4p7S>r>mJBQ1Pw)MuoJ@@97BLN zI2>0hf-vZi32zjGq30TO_@tnw+T$rIeTj7~^SIy;gYlNJ} zuBk0TM}S+wLh|Vw9|^bvd?diTw03|O;0bsDZ2-kE`RJf6(4KGgJK&)+m@+uA3($$v zfUdw`fZe+O2>Stjf$ss{OZGv?$AZ0pom&*%&I0WHye>=^swc{9Q#zyLfC z zgmJ(aJP!w=fds@yBbu$&A!O#vlo>GtCM+w6 zB0zZ+Gd)+vl`wCGAM;Wg!u(la2pca}qDaaGxiT)unyG=1iCJn6nTa02jLK?)(-j^{ z3l%az!(&Vx_f;YL!Y^le55YCLqp+`0vZ^6b0}F zp&}78a|En z15$z203Xt%4-Mme3+Sb$G$M8z!pW~N1mqZV;>U|n!} zCXZ?!NSyE|i1q-lfhWK#;1Tj(AY=vp1e^z0`V$EAfjnRbunoup_JDpn!fbv9a)BIR zC-5VnEU>)D?&3J==gCc++my`Rh#vs<1N(rzKx;5|2iySG0H-S<=kqhu9|V*#N}58; z0v`vC0Y`yDK>QK>cNi!D3IR?$2b=-6L%352PXecbvp^qIbP?eNfLqP!&w!@@Ypn!$ z3_JoJ0t%m-c)kH#2Oa>$Kqjy1_wjHKV5YZ$-+^C&JHSUIDh@IScq1&zFHq zKoMXDC>1adrdKMyRVI%smn#+zyicNjv0|=>8FT;L#q)0fGfW9C!)*0f?iVy*jp5WuoL+nnyWL9X#FejLcI8k9HpQJY9T1 z+F!tX;2rP}@D_Lj{0*E24ab#GjRP7LpacAlJbvbp!l5N6a)hm4nYm-}Y;TJU{Ifhu z9#%qEO0yD->+l&fws{GYW?t#0a+~F)r)NVat%M#be=@Na8sg_0+^q#GOTGD^YY4jj zs0~L)33Z?TxX8`HBT}szY;Wt}W@}FuQv^dwu@=m#@C;oOGzqldT5!TAG0%`{z67cI zNX?I5{_ak@{zFg_#cb^{Pf(*4!f@3lN@@Y}-IUKkJ|%V+jH!x^P!BKGe`6!`Fy~2? z`L5eNwblWeX^sQV61V%NESW5BE`$Z?Pw-iRDJpp6E0c!}URb+bdW zU(*y0yl96VD(^+7?a&ve$;=+@FG5G*s4k&r*2U;2SIk`0syJDO=9Fj;@(HvOf%!Z% z)ChDn94_A7d&GILTp>hROXr#H89lT|C5cqe0p#9jS1phaZ{^{0dEC3MAa}6^W4K7< z2LgOTHk#=YL1zHEHHOtAYs{Rno7vif&`l?qQbFL7Arl1Dp4ntua_lq^I6?*JpWVo* zilWV4+6l<8&=T8PX!H6(Tb2a%RI9ixP`}P-n&$+?-=ITI=+*~R(;2}68sv<^ zcPW}<1L>%<;N&s_gN!vc!ez(?yB1HDLRz^~B9X%*cH8y+B@M^5sEZs~ib-VS0!IH( z7Z<@vUCopxy9lP{&EdClx5XAWsC8zj%|uZn4z{k?bI^9syJnh6{huH4O>s$lcS8`g zv~}chwI4Yw#JJgAKjdUIo-7s>hir$sw8B+zR0r3kbFQeQV#+{zk4m)H>PmxPe)^An z-cLE-M`q=MWu`7Uf>n7V%)!>3`==AdyP|8Y>q$c}v!Vamx6?m1E|ta&Io#GhbH7n5`CXB=^ z$P-}I%CnDl$s6neR`#|ow$Ao=8^~`1#7qZ40}w>@vfSFMQ&JNUaQCC7(Xaq6+N)Am zU$f|^DWVi^Y#0R;>IMtEiK50J7@YCs@2UOkzZQ8r+M};tQ@WdAqG_q4Ye@&(gamaB zOIo;HFrr@W!f1SfneUF8`&&vKxlpIdIXwg8-D z!Dc044h;!|%`BsDTEQ?U(STN%iC@s^9cZ%9h;FtLO!2vN=n&AfB7@cl0w|qhKhS;- z(kXEmf&zNRu?O@d7zOnj)3(+q*pwQEAhk2y;esRR9|Yzz8jEgc!kMaT{Az4nxlU}P z*cY3~t_|pN=vfwm0vg%|B3+=Q&WPQj9c_eN=8sXBjemvj#h3lhEvt&cj?(acO^Iz$ zb(JQR7b2KaPFrC_okmS0YA2ruS^iC1ps!5G&O_*!b&v$ z1;=KRz8Az?-&9g&r(fG1J+SJxeW;0N?UwNV$dd_<$OQhA{`$R6eAWS(05)}*#(6>V zyR?ymr&P?rJF3|Z@>TkVtlDAVpdSaf!@#NgjU?idAts(d*Q<9jRC%=J3CqR45q^db z;!L7U1m;Qbng z62~^(*Y9$VK`&3&9rLK@Xi(kb{xpLZO{d(@shU z2UQ*&DioaRbaIy3_olk#E+enB=W2W~uj(wc#@BmoJA?WLMX-rVmTDdkHe9XV><*Q0 zty|l+RGV`sA9UscupuVM-Q4uSyo-fr)GD5fpe-y9uR06E)z|9Mz%D`pektol7w~;R ze|14E)5y9jrn0Y{0NKspsVtx?M%{9n*cJ3^DGT(j+fW;;DP*V4?@W-PZ$<2ye7Z*cNUX;H?r?0ctel{V-nWp(0&hgH8o&2D?Gsol2Mtriw(D;zN$8+A z#27?ZnB0o=d!YL84w7Cq{*JxRR@!nDr9ms(&dnGL0@h>

6N|Sn`>Kt0y6FIBNpbrK<2I_14 zAeCT7?|KS#;jf$cLT^6bO0!2!hxJQlNBW1URV)hnNoNqn`+|uNrTAh|aUzu;c(tL6 zen{*|JwL_7DMd^$qq=_RWH|6LS!;UC)LlvUJ2*xDK2ozis})cCD`#P-*lf{L4M7gC z3n57+eeB2%-$*L1rzpE&C6OwOW_|}r%37CkeY7f8E-gImF!r0Owaa*)Q>iWY#9Zpz z3$lOSFOpWcd>G2JDc04UGpqGs{UxGYn0=8%clw}wC=KZ&IFVOxs7-t}Q~ga7dc#Od zJ69JuH+rL^Ci+U;4x1QOo6?}#X}NQu6tPApmB>_7n#335b8#Q=64RX|&Q8+cF{UBk zV*@4CNz1-R{UQ^2Y#Gy?(rg#w@1%ud!HqqwufA*EsI=k=L_#Oa+$?B#Unoef=U5-H zo#*?a>5a%B=*z&oq?hE%xfbSYiz~nVfo(?YA)Pnm=g-S{ZyMu|<$(5p0@s0l}%{fG?2V+WpB@^7e_s4@KZq^Z{1Wj>6fPtLQnHsM=5IB8E zX^uZVMp5(WAV6Owgq;fLRK0iB-BN3X|B&%^Ov1138^U zw+idA*!ksY{EN2BZB{l&=3To><2YzbgZz`nTigdvSMY=eH_;31+SG2NsM>JMAMHj- zi|)o#JG$r|d0!|h$pJ2uj{a!!0tJ2phc~|JhNCHaB&HLW(KH{)>K>yhZzHk;=+JOj zMGUor6N%r$c|Q`t21+0Ebs2@|bB=N<9T@?8k=aOrQYW<-iL6I72-_L8ES6etEKP#tP2#qp#poo(Cs)Ymfi9MKGqTV}*Lh zLCwQE=|r6Vm9sbhk*G0pbpE6}IQ7te1OcyQwrvgvKbX_&dyzm~8f%QFcVU<)){$K} zIzys&*)c(?zT?q%?w+S3=E(G@>LhY__x(KKw69guH!I{EtVVZf|3q+*0r44*V}?8O>c3k*LZonHiVw)) zy=E=%GvBv~Y&Kgii@vBDEh+eVU$?FEZT7N)#dguc$%0l}7rDkLXFB~vN}m7b-{f)- z%s!gZBGD4}Xex+B6S{zs&rPnHkZtXRkh?M^5r39rYR%Y!;UuMgQ_! z-JaWJ3UIF!BXz1_JD2to3eWSdU*0;_lXDW+AFh2(Gmlpp&OsSx-nU6}u?C<;#yjOwHN{%s^ET*}yPS}fT{L3-6B z>2UgIZNc?kIY-vZ(!;tx7eFqma;CTlL93X0#TCo+^}(oOqCd$Y8kY-$CgUpxC}n@l zBfnodzxR~2k2Z=^hnd!Fiezj$?ysZPc1fC4+C7Ta8c(5f(J-7OQ1aM&6u3>d?f4Bp z%aj-zOOV6er2lK{N8c`9R9$W;D#@5a+8F3o8U#kV=-XXW$d{8O_C~regdH)ohLhw_ zn$^sdsM>4_l^|Q5?4-`Fcp{L;nM=hjugI#L%d@I~t?2(vESZ{D6v+sbd7(^(wA8pm zu@%p<<=U3$sb)se!bz~cif57X7PX3N`jXlWa#geh+W!xUWj?M-!zp<(oGZx+m9CbR zpbPDk8BekylI;|wfUyQ_BsKABE@{#wW2$6^+4|Q)W2W!E1T*9r8U*EPOFT)DifVPH zNkcXAL+0C}U+41e3Qvj{|I)$(!R}1PdMnkb3zo7_|E6YTiRLEBmZ`K^YN0Y4kvbmR z;iMTX4TSNftifgp{&)vPsFr8cYz9ekEEn)nghk2@Xodt(7J|Q>`#d z^3JuL6Qdsdf*-5;G@VPs_p@PJMmCJ#mkDrizU*xCiq}<{^wWU&chXNLtE!g&f{+VeWl9his=}-mX}lfpev@T}yJ-4SclGi?0mC^_1S*^i%wF(w|AnbD8a1Rr&`1*D!1_iyC_N=p%}DR4SYk)yi*7!Hwp8<+s==9}lWj|^ zcsa;1gaS6ZFAe|B>}6_c&WR;7cP7+)OD?-6>*koZ0evz`DgIhQ1)y-PwN$#Ot5-Mm zVdj2|`lS@jky8)c+x>Lw@TvhDCYI)OUP?7)q3l3Vun!RG<67;9aXn_0Qbfr)IVFDCAA8wu1XaC!Aa|B1N!3xQ|eY31D zdfih=n8|e7 z``j#)hOKaAy;7;x0vIEuN-N8Y=S}k0I=P+&g?!tWfgBce?T(LC|A{T)%NDi_l)aHg zgBPHddugV{%C~dS zpJ_VTE`$j*O~;>l0xzd@nvA%%GfMEb%nsAb;M0MxMP4vgt~@|){o8F6MCnNE(2L|WX?m{Hs!%w>bt)44@Lh#Z=dPqN^QUoW4U zjJIlVDz+yX(%fH9CCR7@@k)zfpkLn+i`s%tByOe(H`lKzp$l>T9kgDW<(pdmy1rmT z+iB8(0}Gw|8|c7d)b?Tn6`?kTm(~GqBXYZT&rILbDQp(*Hn}6vU@qaY1eETZC=#Le zUYcYrJ)^BsT`q3_Aom%DN9S}ZSb{$KxJl}7!vE{ ztkW}T;Zk(#d{A&xPU}5v+TG_AZpEQMk;RHkI)X~%rNvaeA(Lt^gOP2_qJU-SCg*K* z0&(-o+od|HKI~i1Gi~l$aFAD&TVzLqleV0dPu9F~HpLP2+aQ~kli;nj&6e6@y$=>Q0IrKCIN_v+g@i}&A z*xY_It`7nqdGe~Xi!4{5pDTDl28uS=Md2&(R)Gb*SOEdW+url$bN5IibI_G*VXHc- zCW;M#UxGEC-}Z1aUn&!r7scB5o#@;GZ&C0I2bg)qw>pe0TrkIeJ-(Ip0?$cnK!16tz1*A68=!%x)<8 z21A?nIrZ)AeH%+D8iK1Ks%>H%syqDGe52AFoOgS#LFaThAeG%3b7Y1|SG!iF6gUY_ z0ENo{P#Cf3O`q5F_dR#Mlp-8Ce114kXLHRrZx$q$<^<5$HE4AVs^_AH)sh=m{wW4W zFpB7fq)Nr|mUMu$sgPnG2zk{$S2A$fgsp14tfCO69Uxy&xbBgqSZH@}ZjTNh8kbUJ zKtHun_Sn4_Gd~p1xlo#O_5iIxS(oH+$wPU0{FfS8RcB_GQrret6O^soq}Y2&Ylr00 zoDK9C0&1_K-?)jPCT(J7#Xq=MO7PbKvPgqq`Uj;po}Faue1A~Sm!%Z1QI-X(Z@BWg zP4Nu8{ltxeQR`S7q_HTgoR5FHbol(-eS>t{pq$Zveo^qnX}`ik`*m;O4G+;%2tPmt z>2Q?FyV)@RTD?j!>8u?;tj!1fS_`z+6m7~gn7`R^P3SKec`|$XB1Jjt|6E$7rREij z_nBC17y;`btaN4YKg5%iB#TG4*I^GIOaH7Zy&X`)3hdXHDq9wiCa?c=`C@JdGvHye z>PUE(E|E#-DWz5A-hF%_ol=8*Eg|0${dbMY*CKLN@Ml$+%g=6n{zsR{S52P_C#yrgA)NF%wx3+!k#f$j%g%i~^frVqon$X$ z(s62$jW#QZ!3Uj?IS0(dMLd7U9(Hlv7Bu?MIQJxJ&RpNxx6D z4(;6JFF#Dq>|w%3qU}3y^Tlhn_|#Bby}dzQ1Jo&cm$qK|ebp^d4ADX9af;%0lvO!F zU8`lzABsh>-- zF4XBHNz5Kw5~c1G64jH=kY$b#;yNFM1|UqV9dN1Is6U-Rh&ND}lky|!=Q9Rbzw7Z5 ztDbmRf}Aa9C@)8FG)_^Nqb3J%YV!df&TG-QXYPrg+Va|2>NjaUSEcRIM zIx=6aa>e$7FP-p8%kAChLcGP|y$2!QoH5LWpQgMyBd620TpSUWAqv?8BDrumuevDg zD=49G64}zdJ=mAlyC^CD{DO_IFJH*xn*n)$JO|Hn=#wqD~e(i-Nm?;`C15A}mfRI(RF`tp)gt6Qhw zwLyZ(0C5{7_T>9Z)O#O{DwNXqVXVEpL!11vQv)^evSg_ zu|?#uA8Y^D)`Xcw+{#QUl3sqe(V^Y-8-8y$vmxSrd#wHQizxgM-WXoLUoh0;*#QhCu1yPpsCPM97oXzoQ(T^G)|MRU6 z)}paY4hfYg`5=1vMGDJ<3*4Bks4i@}%H6~|I_rEcxhZAm2|s+%9B;W9l#`EXQEG#!A|YuDN{^?t zv#&|+{iN4L?(v!7=wo@8uakU@#uT7oU(~0lgeo1vrnj`U7HUb`Ml|lQ;8*&B^ov7M zcSDV))VNTvr}jq#w~99DPR=@)Z&0nnco%Zg5e(DMS0&}mjW3p?avW>Lrzrnb6E!^D zgrn#a`5gy&;gXjz>BWj=#{_5Xid)jASQujV>T=DkZDF1`NMJ+Se2aXKK|49O$l^F! zwhH8Yf-0V*N{L2%xgaGO@l~Wu>bmrfWUqPmiuU_$TFt{sK8V|doLaE5-kPwOUuv64 zGmdyfx91K$KaT1)-J!Jzwf{<~t$2F=e2J&<6GGjp;rzp$_!oYjmYfjAtNf|TNqi}s zhVLVI3SYXrUbgYf>?WCVeB$2S&HT>bZ_6NF6Zt;v`<{y|bYE~(&UdTgzIJV9C)*2h ze)f&%I_)}|pS*=Q52G=b3ytFrjb8f%adz8jWgq-+l;~@frMi`KM@^k0$(ZJA|rpKp~ z*(tPQZf9xdvG&TYT01Ujk>YVMfg=Q}j#W(7^E{8U;EyI1F=e z_>}YM!A2pmkx9tmzM!S&r-fh}{%&mi@K`VW373(>Mvk9o6CM~jE;!Oo3NYt8U_+0@ z@k2-0IOL8yBfP3f$J%HtD5hAj$lY*Vcu^T%lEfn@FerG8-H4IHM~nf+hmRZ@HZ*KZ zSR}Q3A!toLMaS9M*p)`;!b(jO^1d(VQPw@dQ~)zNaZi{=)gB5pa!7Y`$HJ3Cf({9i`?^n2@TX_ISh|A-U>_V(AqQ*9I37uP(|gEYhj`pp(p0j z*iS zVWBk9L$gTbNcx_di27yHS$o0bY|5rcDxB!4!CThQ-X%{>k5t2w1A&9(_**(EVi@>8+0>7p_kevu_Lw`>u* z^PR?_Q5iB(OJyl!#YrNer*!GHr^Yxp`a8{A z{VJ7H?ikX%(!dxDZVC-^6IVf1D)(G-D6f*rm3D-n?BEQ|R_btDuwdiS%^i+ESFXxc YZ_>OHBxALA(`d+StHz4|4&w6v16jP3$^ZZW delta 59983 zcmeFacU)B0-z_{dFgi!YUI4{jP=j3uL>TN?uoti+4n;u}P(fqBsENIupE-gO#ooJu zv3IPoMp03*#cu3ieb+i?58>v`llwgPz3+cH9~WzX*KXfk&prclJpZ8hoNLAB)Tw#6 zsJ;88KX&#S9@22<(2S4nE?qv&IMAu#t$gL5tuMPbWMIO2dmS(R+};(+j?XrzhW4YV zPL}}aByhsqxn%;k>vg&UFk%7+hg%V`R@j%2i~0<3A+Xg>rz->Q11<>uUc~oCRgCWl zrk(|M0M|2W`J-h?Um?D5KAo-v)DKWgf}enkfTOJuqpeXo-PZh?OL2kW;bGA+x)gXp z7sDfm1V)GIbTaJ1uy2{P+Po3TTBCxrW*vmh@*~2AheedFq;_*E(H#Uh+x7X{BQ(^M8>EET|k?dJ`K$L$ArBOjDHEwATs_Q7*!>tKxDad zz{PYyx`gov(8IRqeHIX|M(7es7Sjr_>BFpXqgmq>=yU|R)gHT#d}U$xLp}~-TQD8& zg+ghY<*5d9v5V+jRzDU|?B8GI^M*3<=}=kLG|{W^VA}mLpiJEzOlM1?#i%afJ!}`S zH7Y7H%FP-pIce!1KxceVXkhp-`1lk$+Y%ZW?G_v!7;+UhNB1vtVQ}tb_z4N<>;trf z6(0dt2De4Q?7hr#8lMBBeF?+h1=Ecdj{jE`50lT^m5H}aE{_U2oilRvKrR%V5I8(0 zJgQMlbaZ5RU{q9K9C=8bPUnv%uylB!x*ZxAH6%1JMi-1s?2eddx8adPtU8ApTJz(E zBO$Ios%z;VfSGPcSa2}pKDw(A*dKvWA!@?2B0*qKWEAu6gU#k|6#TQ`S%OD`+3zv6 zbUO4@!YeSx{JOl$zCz%jZ?rLuiH?loq^w^}8;zQ7S~DuZE{@bkVAHK#V2(1HtFDrH zb+p=JB1Wj*IoH+l+1B6>vWKxo*Y@?aRDYdGKi1bu9TpxqhS`TkM-C4T3%A;aCKjc$ z?Y7dQtf+UiRaai#Vk}d0RYNUzokrRKFM>_qjtM(DCNO4Hv^6?Serc=_|4UV|J2cUz zK`5B1BO);YP`6^%>iPucw87kChv;6xX3HOeIk3}3d>jTO8u4-U-8l@pkseyl4F+?S zSfhgiF(s@);bEh~bh>W3^-Z+`CWr!U6FqmEfnE|B9hzy5^%5MxT5#DqZ!pr)@s@H{ zzA{otZ_Scqef}~9B#UNUb&@ORZxa92M^p)BKZZrSg@i{A*6nGowJBQYZCYr)hr(vj zgQEh2tf;m`OD$ahnEBU%*$08c<01lMfL;~Y)Fv&(o`lstg~ii3HC=UyXgniMUEKKxXw^?*WfOi-C5)w9NpMmhihFq<*H!rR6oNjOvUC2Hut`C*W7E_L#yaAY$kjq z^gCb{a2XltzIFJ>QDITmDEXY^*lu7iEt73&_kztt9l@O7C$!oUZ1I6ZBHYG?jnJ)y z&O(JZ3G?Lo1IAbN8^*Q*=PH}TxKIs zI(O?s{dKxJ;JIMz3JHPWdf@E z*P(Ok?K(`0uL9;Ay*(7Ch^N)ma0GSS`QoDyux*86i&JlU1(7fYp0h`= zS!0{9=H3$xLcbKHIT(dP=pb(Okz?RQer&j$J7Lh-0|US;&uxr0*QSDtz}`Fx{m+Py z$PpMVEU-~p##LZu4CV&>x7iU0c4;o;zhZ>L5T3%jM z_z89?=rh07$~TQh|Ffd;5V$tN!CVbNBEd^!V8w+{04pdqS{vK9;4-jp3O)^H{8lhe z7k+S*<(OeJe-fCEP6pF~(O~vKSbVfwlr_W}YlXlJVbSU-MAsR1Y1rex*YvAkwyXto zc5O{CCs_q>0q`r);yYkABpu8Oc7vI|%4BUQC&Om?NHEKf?|=YX(hSTD3xCiGt_7Pd z`W<7*N%Sk2Er<>q9*H5=4G)XPE}_${oT8;)2xdzsgIRC`FdeQ8rbDJ_TD&+9>DoX? zeFYQtA%Y%No+5uJT)py-)3x%(fjRd^f*JjGhNicjDYqz6$9cdkZQ!!8b{Jh^w#EUo zKCfJ?b)@XsI4<4@Gadfp{Gybo4 z2wOvJcLrO7N+LZQWDjQd<|JwPAA^hNI>56it2Hb*PPZKuvxO_coG?kkp|Ii6VIiS0 zx^0UzN4|oYu4}T^V=ci23#mmP}70DuT zo)3($>gKK1l4D5*1)}P1YqS=$0kgUhfiaLQIVrULjTKW@V`Er z+n&jzVtJ&|>F#gP9K8mnBf()IqoS;y(YjL*SP_oTQA4aTxPRfn++ z3vvq{enK8uqJm!H*)4wWR&BateYuT@iX4FhYUJRdcyx!(%4~U7!{#(k7P>kZaIU3T z9?f@ZPL7F;8Zss-aD=MFm|~FQ6VkEXxE^e`sstn|1A9@Lws5U6 zp;q3ePXD4U+*EKW#19c%4$N&X&>GEsL1z|v9JmDZ{KCGzOIzs6U~|FG0GHt@q9X#1 z5XR6wT!XDap$!}8bT5#BdRerPJIGo%S{_{ffKFEq95gsGis^?(;(;l~8fApebno_S zqY`C}iHbw~b=Y*UetS*#IHWCnHGe!3q#{98B(QbSeAty?mpY;ifvupAhqbM)`cbW` zOM;6d-KgQgRy+#m48k5fDma**zS!tmwB!v>??7RPnE0S<`x9TD7$ zvLQHwKmDW~)b^xn`gF9s0`#yGS^@VF&mpqyB|T4Sj>ZfL3$fy3p21WBlP5ZA0*1sN5Z3kBmRKuNl1a4$-UsvH*ZA$Vv5u23G3Y+Cg zV9uzwXVsC8Pk4Yp5eOH-oD%6^b#6ySg#-@Q=~kZ?a~n+EYIO?^i;9jJVjVmRM@XIR z`A-(2bM)A6F#KgqUyu_N$&9IYE2s1Cet^(B^963Kk)Po<>`T z4`EB@T$0Uq~Ia+>R_}dKB24_$f&?EZi6F-#5o~?6C^Mw$T}h> zT9nP7DTe0Z=ku|PAjc;G_;p%Bce)}!o2zhhaSW}HzV@j5_E=}F$S}xtV zExS^vULH}!w`fLAiGIiYU00R%@0c%aS^mm$T9qa8psFLbU9B3cm;I~zZcD2^NHWDX z>i1njYPIiW$9nZl-<-Vsbi=t4t!3YOQ%nU1t&$=;FKnn3TdDVvyVN&H*i3Yd;hDW$ zsfk%S4a*mnQLfa;ES1;mbWPN_KzFnLjGR&5qBqJ;4J`WRasYlVkP{nNq?-nvu9=!A zrGZ)REIT!{NZ;D&biJV2spVXNso z*u6#)gpIZN0SX!&t#@Z$=PW4T1l{3s1X(6;$NS~kS4NpvRA9rtK zd#nH-Ik|zSewv)&Zjmm*?xZ@1W*aMG{=3VW?w#NqnSm@5t?4kYG#%^FhkjVql{rRL>G~h8hA^aAhw5y{zWh3z@md%5B0>N zWc%&p6i+i9^|nZruy8pZ+874GVhVK(^{eCni$%HvjZH?b24<-u?gShUdseC+Av^h4 zq~p*yyVQP_ieQ1Xg=JLJ2g70<{Q1`11Vi(fz4s25Hehf^`lcj$T207mhQMm17LwK2 zEG>Xl50*)F{DvIR!Xg#It%fPIzV(qapiPC=Cbx`CSZs`%LaJ2SR(>TPvpzu1XlXIc zg~q07lZ(sdS19yQF9$X<S>HbXt12w z*i(OA&S-6sN@7nCGo_i?p&Kmvf;p-yBd4^jtuE4)P#Zus$dwwK4IiB3q_*CYx3lJ` zIt>h?on>cVZ|N9BZ4fZ>2K%yd62vyR-P0AloYKVX@I5S!q*g^>3$2P5P;;Hv*OZ;w zS)@5QR%lZTjg%e|L%8ORX z=nH8eERLYoPYNu0tW&dHh9$P6WV612oYBD|b;rG)Qwb?B#>-&!gJs|tJA8%3kwkat zilTJ2F|OS!YK~Ji@`tzr!$*V$;=|#IKE*z^Q~smK2Rhc%%ks;PHT3IbCqIizRz>ZG z;*Six5ql#mLaJZCjgYt=88GyE)4r)s(59%9xv zl><6i^p0|3CyUgrhEDela@lc7NZ-L?tF+~E7M2*IR%WSyt2U3(Lzw?fVX-#MHRgj= z2NpUOaqD3*pGnSYZ8p4gm6N)7OI2%XU5W{fDLhzq>T1z1kpsF~q+5T+j4?|twRE`2 zp&4=@c5dvW-7IM0eQi0QyG4pbd%RGBIvCP= zSR8Y8DD^jGrydr4133Uc!{x*t7U`^;<}5ZvEaU=c1qU9p5_R~>0X;1aOQE%+hK?;_ zoBoC;b>wS3y^U4ssxxhIGdZ9aHfdNsYGqjY`s;E=FN?mI?9|&L^?{dM@di1thgq5h zi*94n!Q9)2pf4*>XIsAd+N9T-=_3dDTco+r*rVu_t?nim%#4i`Q|~h@PFxh+!YnmL zQ@LU=oO9jf!~l!54GJsH$JF}YWv4zCy{jD1$07}BXv>*W-)!0fi|MrOV zs5d+*78biyD|S09_FFy{Bt3`K99Bs=tEpM4>!DS`rEJ!JFFOsgNL!(4cPdW*Pq4JD zyOOV2YJq}K0Nh8PnP9M;7-=7~v;!8a(QY;`5Tpwjnr3EWZR}I6eA)ly!B#eC|(nMzu;e1F!`4GQbk z`g|!YF&?;GU62EUEs{NkOEdxNub!L{Y|+n_okDP*MvT_0SxwAF6NaZLZ&*?bggEHh z!Q%&5^Z+$<#SsSPW&=+6oBoYl*0{76f7Y2vB3$W9R!eUu!4pDX0V2<)tF zwLZ(QZY))>$8a@ZCqyHIV6i{7u~-O;{ig1jrt`4q@t@1J2sS_}YA>7oU@`BX@spu2 zzk2jA?S{okpL;YhJZmRAkMNd!(B<$~oALUEa^eV!bOIU^YjgM`EDjmA;}&L9uMXPI zm|KwPXDBQoSCQ^Pp)**z7PHi~BYzuBM^Z4Z>tJyu!8+h>g2B;Jqx22sj3|pS%nyFc z$)29lVuY{-qCWz$t6qTB4Ho(evuy&(@R417J*9&Pu?%&789&mJlP%3mooz$N+eVa} z5o0l~g4UD+BRysanbc)rtcn%jEoVk~N)Ze}*B0G6Se$imF9LJ$&p1pGm#$g~m@xkC zCK&ZpAJ9bokFwJkJWW8;W(cOUu?$?toapLl?2Aw{h9m_cZG?FIJ_8Gj1MSFaX_g9i z*G@_5W~^@~XT(~hiO`TpI9H&DPKQkn7FLq66D+grGS*X?j1bRP(9#9_h=Yiu^HhedDxoI!U)yq)@R;@rzNDL7Y$!qR3RHa-1nIpAB1 z@h&v2WEUJ4IA!2HhCBckXE|Edn$HOV<1L0uz2&6w-cmt-%{BFzL+S{NO~TeS)+|l_ z)9P*37m*Xcvq&uhG$(a(r4X|e3yV93w)9WKVx`yyu|Q3ja*bdiB_>ZZSnL#(+}kXT z`CqK9u(0omI9=bomIW4WVIpocEa4wY*#ry!P($DmcT<0zE?P6NuLTXjFS~NB8?eUY zTHOccjXMo%q%F?qHAtr$Cnry6WGMZLm%^DmQK^EX)#dZ+i<1 zeV-u7fh*iiK{_1<6io@7N7-3jt;~GKMuhS0J%FY4JV&}~n6@LS$4My>7Uu-cy$$dT z6ecH4^)_0Da%N)9>EmRlX%=J1FrBWooH?_ZJpwIdmua5H7YMau$lx9>C;e)%568?@ zV-6wIK@B-XFirn+&Fm4ds8TvYS^))zv&`h_&Gf@%=V{)?#jty-X-Y=Id4{Ad2;oM~ zF~CZE4y&`8qW1`$&QDFT93k8yv=q`4SPfudis2;bf{D@)RxvrSms#opi>tbndMBL= ziz#uy_i;DDV3*@&*UPNe%T9CDk7DNh?SqTCPJK+zsJss@#blT)TZhXYFyquwgO4=E zr-7Dou%LYTV=23HBz7Is^^8QS)tTBgRZS|RSw znH>kk2MP}Aoy^iMSR5g^if7-MT4FpJtx^p(7e*hmGzU?vP`h0mgT)%v1FiH0);F-Q zPvfbn)+}xNP&Y;?1eS0VpH3yulKZUomaaf#r5KVK?xxwAfeyjlVHm8Ah|;<)6&5=S z>%Xhn@cV2zX^pqkVUAWEKJsge0{|@Umg*C_Va*)5&suNeJ&2xiW@}HW!d%-C3f*n! zGgo$A=WSRySMIaU+u=Im%&bd?-+rO?+H%qEl760iZJoE#S5`O2b)Lp0xuI-?uya83 z{SRkR{|(LT5$L5#pK?Rp=BwKZA`!rHL;7rlI;x>oKdFmgW3xgCuzOKAKK2uPry)R* zuWj@;9#=3eWS0m}$!CGq1L~uJGy;|nGGT0|nT?xaHIy@BJ*B${u|w5!y;LDl+pRD< z*sVsw@=)_|YOaOlsg;0J*Ztf$p25l|+2XLd8v|hVl#_9|-G~rNM~7pMEX=J6^Uwl| zTN{SHxw}0K?YO^5$e24A(?_s42eBJs%DXMn+90Vnln7WH1Kjb~n5F$9PW`0IU`m#q zw|kogBx^g%pHp}V6c&j2gY)=3Sa^PD;AyCeU(4_CHgx-0?z6*Ns=e6Ob-d&Dg~hJZ zKAvAFEOZg(&~;dxz*y(OW-0#?Z6nbpw;wDv9#e3K*)Vm9?40UtIJQLYlj<#fMqDSv zX@}MhDYlyx?v$p9uv#Ea^LkDj$pnE;W9%>!2Q8J8(!8a`OLGUbiP>;#sqDPVTXJ5O zryyfDSoP%OiOoz1a4De$QD##bEY6?YUNOFd;vpx0=V_?BTu%DMTN=3B_RNEGvtjje z*?G6O^avu`gL^K9rrL@;^-ES*>YP;1D9d261z4D4&88Qym`~f0@Y@#qmAvn{gm_9; zgxaV@VuLg7g2i^`IwpOF;toYS`ZQjp6^mwIw-^Jf5#lhvF;~~Y;#@^aOs;#daG;^9 zuu84grW)eTyPIIJFVv%#52&_q4_l6Ccg-vd?S!xAKG#59NX|ULWd@??0 zl%B(4$G~3?vs86sUJnNeOZ^3nvWezMMtzubG#%I1bU60KJHF~u~_z--0in;Ch;-W8zJ_n zy7WwAVW~68_KQMk9~99#jK&*SY`MCkq;Ixr?Lm(rE*w^U#Ho)w(pgyAEaM%@uuUsP z>sxnN93ssc4NIF3?1zmaCHe@~Jy;wyb=#3jZ`Y1o__Pt{ib1gO@l*p((*lH8S8i`f zr=hS0ZF&~iVXJ|@w1A~8N9^d*cd(dJ9TUTz9kTOjZ^Ne@avxByopRD?Z`0hJTJ}Ge z*9j=vC}a&Y8|+f$K4-io_f*YS?72tH##mUb)T7-VgtQGC?Q?hs%NOjk+YnM8mL$U-+qeV{akqz|J%7a^q&<_Rex zG&t;&lP-80J@%ng^++3mkoqKO+=-BS&^CDQmy<4f8=4-FuU+((W*^X2t@`^zX+JD& z^f@-~VRcqVqf$e&vCTouUpcwGr!)hhhU_)&ONNIB5b`t4?JeWV#i`p zqM$3V>cNt@$rR(~A`f5Q&TNxyj;79Eza{pKxIJfaOgrZaBF17K;DR7y5Wb7A#U z%d7OlY^;0KwqU{#>IfYR74__Z#pQvChF=Rj5piOs+?PzpwBE-0?_@R&gT=&uPNWnl zT%p+AnwlMq$F-xW9p;9_$*exzNu42UivY7tngGiaS+FE_o25Oln%N346i=6vu6au# z>A4>v1iG7GuwStE;=Wt*gcgORhv$qjuv*#TjJsjsVXB9x!=RJeUw!9;BL&ei&5xN- zElBO4F89;0*cj|5cuF;#(uNT|iJMAmSX@-NgJX$J6mh5%al2u0v0_ug;phb{mZEO< z#yY3j%N+0+gnXc*V@|s3Ps>R+y$vr;%hzst8(q(!1LVwG&Fr&vH6Lko*v8kAiSE#yvtgD<|FdmTLZL>$Mb2r;)$P&RO23)eu=_?&ugFLc!w` zKHO<`PJ8e|6EMs(U~$xJDJ2txP7t(>z2bST_3BZ~FyOp;2-pfy8z^?dbCE>b<-WOK z>pa{S3_~u+*Y0|oeuDT7E6Lr84?$rO+KurGEY^t=6bkHjQ5$7#qg)P){g0H5%?@{9 znPJ&uG>hks=C(`P3c-l|;BJD!3^3x|^_OMm2i{W9W!oUK=Ta`qNf7TqtdE2k^)$0o z;y2qU@fo-~EUq~`A;F`Guo`G7ag*GU8yAS9*!|zs4iRwSorqYP~( zV1LE~91LxKVL*-hVEM|KEj^`t*RQy|A>;$;TqZ-o^%m59QNgaV4OoemK2e z*L=lb;;3MO)k2NqC(9FH;ehVpX*hUYzV;LcSPF>F&tG2}8{R-CslWEIBGeQ*&gfXC zi(zRM1b%ClZo*>6qKOyHhQgV$^K);hd1mg@FbbLh3rALbes~ult97_db$iia&w}sjR$+K`TfX+PiTY<1o>|%-8(=RuU01Hx$UeRRk`lb~ zatYWjs`|gO5n5$H4^$EHWNwqyg`JnF*AzOL`DzKS&A;L0g@AgI?SZ-g6QZBh>z|nE zun5%j=q~m8J7&6u0LwQ6wB1=hg=PS+e`03v0@xxSzyM%wsTY~?Ej9Ch;eyaGTh;i^ zB0iT{Aq(m%BL0b4K{t_(oL_$Sx{O@tjiX%djR~m8ub=WZsa|=RgBA!dey|#=G3_9s z4-tA^rf0!I&&w=tn9#}W!bn@u2&fmC6^zhKm04gEz&;!WFn%<^D=$+Y1CV0@USvDj z;cdLy%pX)ur~4-^i!>N%N9DB`ErE)Pt4K#BGP{a=L3v-byceYwV-?`jTM_%s$jj+ zzlgq!>SqBVlNl^1Y%*s<5n+=VEGld=>n|nj{|+;0Y5br&j(V|WAfR64k_deRX2tb{ z{@>yJNN*PD|A{$Un<5?AORo$rsxPjtQ*UU@ZV~K516N+A)EqzPd`l6Zm#Md=uIw$U zFC!nxE?NnO&Q~NQGuTepWRv_XyMk<=Q&F#zU2-b0be+G5C$q>t!p_T-`U;)Q<_sXq zGjnRFiz-OO=4GY|7CM>15W%5f);5%)U+TF!SvLGu;73+E{Tbf#pNxFn(~h9v8_@h-7)0{+rFr#kq$6uJzZFV#RSt7yTF{AF_2ltmJB3)jl1J9r{>bZy~Q~yKQWOnddFdLFB z_@f@%2P2qTJ$o=0t^)rTnRnb$D3298igL-U*CieSI$0jfk*X>ZkQuBlY%+VGuCU4M zYBQMm-35DycrqK*63mKxg-&KYoxmLO_--PC%!Iv#otIhhAn0sCkccO<;vqs05q7BH zFfjhZf8O)2!^vi`!rh}`% zOt)I-f5(hpgLosi?~NkECc&FU#=Kk;88XxiIvxMso(0?z>BzKii}?FOCsThQY%*K^ z1k47#WIS(QuNVNo2D1h4g#8}Oi_Ee52xb9H#PoW>2Ele;tCM5^#CI2VFECfh05HoN1ZGbJgW2$5cIxqg0a&W= zC$pk(=;R0ypO-0(5IULZMuItM#|nF#V16Hi*Z+&zMa(!JOb_ElLNfIPVUro0h#v-J zrXzN4CjXHpcq-%m!dx74MEpDv|98x4WD);&%>Clg1NZvp`R(KoC z`tFEw?)0z){)Tx3d?$1=9eNLD0XahdJJu`X4f-1D9Qcf6tUn(rXZHMbLNJSwgiU6A z0b!GA7Zh9w%qV{Ahc%a=@n0~@EoIL=Q46RU9Fc(qI*E+`C(MG&igL<<*|2J&JTl9# zF6`>|Vom-jAXX$`!Wu}(0&9wlwZLqdo3QJEd6AjEuCV`(9T4A4#FLrc%O-e1U_}-Y z;Uf~}WoBqDbd?pqa{4mupz2x+napHuz%0&J*zH7oUgj;kyNK^WRyLqG)l%vE$##NW2firWy_OOHjwQ(?aYbEne7 z8#-v9SAtowJ#1E-U+83RI7PseN(!CK{H28MEbOwpQ{tblq7W+4z(r=Ty0FQt&{f!Z znGVzzI+=DIk)Cf-<3*+e^+kLmVaGQ{fGxLxd6Cg*T}xq;`B_2_Fbn7@xR>DGU|wVf z`{4&29ROzffnYi`7|e2m!Mp^=s{wY|a6~ZU2$6uyjL~39vBDk)X2IWrc{7>_X1>W_ zUjH-3{9^{@ohAw(vx4cuCexlFY%=YcU^+NQ=w#}1!4<%pg`St`=vJYV)%mv*0nX~f zBI5rG(}5!>hZP+Y<^2<@>yHW8m1jhTzhf4B7V%tO*T5Xhn<71#72Xy$nd!5HotK&a znTUU`o|GXVz^@GJzJTe7k&9I@3(6;KGVT0=O+wGhbgU3`I>a{z@*;DniV2&{bfxlX z`w!D-PiksN3){5+Uq2;g{cKTfQE^_Thjm5#KYcpPtc+(l^#wNo^ZGkxI@_nj@qd0y ztaS-LtmXAj%mV%|eM;PhzkO9NGRI8))aif2bU^!rQsaL=B}Rw*0Py-d{`XVjzx~vh z`_sRl5@R)S)BUGUhdHkp&rS5-Pl?e9|9(pR@2AAt{p#OOiU0kS_}@>7?Qmz{>FwW7 ziMyjGc$@t9Q(`eC{_fLZ^pB1@5AuKa=`iD||NAL19|CWSp8WSyV)h2E|H-Gt+?D?Q zlo%byj`;UeVsyg4pA!H3De=Fb694-t@qhnQV%&dqO8?6G$maHQ7S!4sGj@74&+J=q zZ_C}DP$|%uaei0D-=p6>ef50Cnai7>tu%FAQv1W*Qls&{>M~nbn%9llU7@=hVGb^x4IHc6AM_<(Si;%uM_Lbf0o; z{PNBpCwX=8%c}c}{nWm%SJtgp^TpwV_ns$>dhO6DXK}4k2j~5ELwQ{OJ?Ijv0@ z`@4%%-!|44Ezq%m{{6OIdmpB)DOYn|w_u|spJ%-r-xeIbY2L;=Sz%*FzWe1#SpOYu z(|Vlg?ltP;1?9oUo^s^sQ)`;k4ypRi+Msy?dPlGOQsfIxbG?;-=K9{sY9GCWvbVXu zgFZl!T0rn`4k4ligucoy3Z@niTv|ftuY|RPkOrY+*umt8NsCumQ(}{(g)jB?#j`#o zd~!86y*(-MO%u0#gZ6xO*naz6yKlbT7F&L3!v=9XQwz)0GhZBbKR)=UE$#Pde<7-Q zGEmXelhBr^=M3u!RGeBtaBKx(d@Be+$_WbT6x>=vuqtt_A;h+ZkVzp#so4gCYa0kN z+dv3YGALYy&~aY1i(7x1J2)rZkY@jWPflRZfu9dt_R$T?TzRy0`IRO1{JeQv)$gCz zne}x3m-PB!Z<-w{c=KF?E?ts8g`66a;IQ;`o?aWKOl^x|r?f>q&)TA%2*tw}g1fKY zA->sczwZ*vmZK*#x(unEWE$^Spm6%415F0b?X%ZfuSN3-vn<_5FEcr2+?Zarn#ZTb zSuK7o(56$|+>A{f(_Y;;mAWraJ&_38E_?qscBx&)-TwX8{jUmj2wC3Gu-tE6e&yFX z^`8uSyy0x8)yAWXGmkV*cRJU4`iTX}U%TIYT=G_`tA{zQyt2qa7vB3sYNoHgqTVO* z%ch)TWlt2_kkhkeE&rDF?rwgy+$(9(gT{{Yn>-0P>1^0=v}379MZ0e4bl`_hV_akJ zr?xU>+9@3-$SpIq~!r(bMHr#IaW zeYd>t)m88V6bGbZJSdlp!>G8C;K99hTZd7{eW;4?(8$e>{jDdspdOFYt(d&9i25mUeU<;hsLMNR9zZ6apt6ZBYy2} zU!vXBLoQcSW_j8D6g!~h&ifJG$>km_Ze*JGYFbg()E$xfiiH&8GJS{Cir?z{7x2lK z_PKPWoqf9(YhLx>_5KTbycsq!?cV;`#*_v7cTbH!bKNra-mtalQ}i8_t5Yy(y{2N))>fuY5CO6sU& zk^B^o`6$SJJ_<^nkAgZYk0?B(;P(@Ru1exh5ElFd;WLHqN;?IDuL5C%0->jpLm``j zLm~uhv5EMxdI5yJ6tKl6LGVw65Rn7{TPy`r5(Jlp5U|BAgpfwz426M8*98zl7ed&v z00K70MGzbpK^VUX0yakq=@i_OAz*V%h7g+!A(H|&$Dbj%{tRK}&k(RVQn*UNYcT|D zYl|UFSq$MB1#D|eAh<7qkh}y!r1FTuLkfN=5JoDADG(NSg-EO7L=hdwra;g@XTbq$srlDaI**Dtz@|;OBbBa{O0;H{bN0&tN)er7xX{ebcsc!m*#)Zhq>YJ&XO--u_gFWAnfJqv)4M^3h6RtGYOM zSyngU!^0aBr)8}Q-7FRNx7&8)$Dra)w=cX`EcR18I;@u;U32tW6PmIqssGpP8)cRL zEA@^_wN?5KeiQgPiLKx(9|Lb6yt`Psad4ce@A5)t`(CY^k?;PCLo528YOSR8d$*_K zeTVQ$1=kMCDjasN$$=^dQ_`|$SFAekP1Uj&J8s*%T5(u~axbG?{X`{hHTofa75ZWC zPts3*8y}}!JyJrRk$=ha74=;%4xCm#t=qGyFAMxMVf5&zwC%z3eB^qUYJb@EK7Qq% z_0^77-?AxXRLf_lYE3HkJ>0YPgY7TW>9KvUQAejt-jkm3dCr70uTMvY%$OCBK5+Yz zr>z!ODEe;Ez)#hF>%J*pTDVh<*FRUS_V}rbZm8?|UsgBtUAdzA#CzG6Lf%TmYWO>I z4gCF4$yft_UDseBz1BjQs!UxA;VOk^6s9X4>mW>73n6(Ogqg}C3hwK0$DTcX?8xKZ zy$)?2G|u%y^J>wFH-i^ETX()jtAxqHm$&9S^l+Bb&t={)r-Me3%vr#`DS+i*6 z#N^mL_47^cJa6U5F~96AZC7=H*L8EjqxXAm&uQ1AWkBP7VQ!tCJMQj(?tJn3MZbFI ze_Cxx9_N#luq`My4aF*FwxFKHiqlpIp<5t~---#Bl6S&23XLe#H+4p(>QBoXPx(A@ zd+JinE^(woZKpj&zdmuBHTKc9y6gV4>id1uy(Zl$Uts9w4eL7I-8SLqtmmZ`-90ku z!A8YlD+bVQ8!B3+#BD=G>02@3n$-DRc-4d#!L8Tz{qfVjZ8dJ6w0acY{wn{{ckct| zp6gY~yIj*cyE;|RxAp8d9ytzIQdblx5rdI z`lgJ>yR`-0>(lNyud2Q-rE%8qwkOQ71PjmzVAG^pMH(} zuFUH|zmAP6Z2Qt=Qh52z-}e5sQiaz=?*#|1Ejy>;)XA<7NB?mAQQ(;ci^uV+U$zCZ zMwz+;#a>0R%CjA)XPx4)6T*}o5R!L7*q}V3;Jy=rUn+!6N@6O6hZH_j*rK#cgRmeK zf^ipwZA#Z&5PZ|%YxDHVm8`J=10MT#>}yW6rmlM8Q{jHT_p9C|t(daomg67a)&9+Y zV9|$Xlk3%Ke&PDm(gh-a2^{$~zIoQ72N}uogycNF?ojlZaoP*Pv>U?sy%6>)Cn%&*aN7rAzY@0(Lg*d{nG_BxHTOes z+zVmmeh7z^3<~KKybeG(s!TlqA$A{xXB3Vr9tR<~?uU?k5W)%N5rwN1{0>1lr6eAL zFy#P*&lJum?G8h5KL}yNVFtf7|Us z!O5{dEgGDEZ_~i*A0j+ncC1%nRs8B zdI|@X2TB&{cg5p0=%F%~^hkL`daN`*1A3w)lAbCrNzasaXF<=E6w(VN2NYoYVhqaH z+0VZGdb_TC-0td~r4g;lUOwgQSJ z1yWZ3if(hcpzmPF(JMnQ=zA&t=b)US@=>oiUxZ>h4`uvCD4+GpNh)bn+%7@+s#nHd zf)aWGN+uM&Ua5JR<8cwf%*zn$lne^#6uf?eU{t351|jwmgl81;D;`%MxL$^kda2JBZ0|*V3fCmtK??Kp0p|K+U4k4RD#P1Ny$}S44??Z5T2*E=MdkDe* z0faLYJQb%$5KO;A82<=@mvVwa8U?q<5G+dEV+f%SA!Jf$uGD-2!SNA)P%Qt1B&gs#e(KOii44#D9igziefO9;L%Anc{kQ;}Xl$fgkS3PNvX z7lqY-KyY~tAwUUx4Z;5LYLI`~gA(KL& zQu7@I$2SmWzJm~?WKc+_;PoDYRhjx8LhM@z&nSc_9@!9F-$6*uh7hJaqHvXhUk-#} zN@5O#Detidekppw>HUY#XP;jvdT(FzEp0zEcv$_=w$pbC9N67{P0Gv<4cAs~6Mbyd zl>#r`TdaZa+-slsuEM29GY{Jh?AR$d{JU0pwwDN{-3Juwo{f4oe8A}^lD{eum;KjY zKRuOOnYQP9ablLf7_B-ym^~(Ij3D>Rly>^V)_+j>{OK*-1JaNc*mAgmfh)Yjq zA8m5?Sf^I)e>qS;@?(#$N@g}r6a7EJ|B=d?kEm!tj=qpm=##!99&Q3YLGb;6n)iM} zicyO68A3LNh|dtlD7z@E{s_V43xqf&>(jd%t zGj!0$&yO=;XuiPAggHT}sfX?O73pW{Axu;(Bb<(>zZ-Y(r?L4rY$@n4?P99y$-7zS+*jrCBw0DZ zV$)b`^U3Fu=9Q1AYneIucKU)tL!%PIXBFFYs(Ft=K9$a8*?l+g;_&Xh8u<0y)VfBi zV^f-L_|PriGQW?5rq^3HY;;f;M{Ay97b|fEQEaFL_cIF`aCXl-d-ER)n)LWV#P(jR z7yRHVmSsvtAykxJ02O&TKvf}n;o2!-?bo*Z-mBNd_eCRW``LM&`DMxa2XDVySuecyjM(M3+RpbM zx8Yc^DR~;SO7SR+VqFWNp5(%)XN~fR!c_`>MIfwG5{p2X;sD_@g$+u(q7d8*!;^Tg zvojC3C_kk0l^`iaF7kc9Zx>E`Qu1rS7RFNifAdD{sVXtz6LK+3P z(h&A5ait-ImPGR&dH1|**s*(>G28y-wt!yU!dl78-gQ3zxN5}Bs~*QaE)NQETUT;U zXz{V>aaT$V2++B7e(hR!w`;2t*(pENE;LB{`*7_O@`FmvGAP!u6zZ8-2K5|PGAN`| z@N$H3RGI1sA+|JxXB3Vr9!?Nk%RoqWf^b54MByq0KWEIoQ+a3K@2{WMUHyaCm2+RZ z&A8lQ>DXQs_mAkYM0tIAMZNCVkB8hDH?j5~ql`z37Pqgoet^^Ge3ee#)HjT>?-()E zf4#%*8EcgBj+lL)Q7(_}Wl@p46DrzJ7Q(Me4uyvl`j>-nURhHP!UAUq4lWQbDgiDK ze9J=EOX0F2m4}c`A)-8lE6OektII)fsQ@8E39A6X-vz=M3fC2y&iZ?ne zzF+_Phz{P?rgM%w*PkMw~OeTXV(9o*WI;Cn{V$pe}bFS zf|tpr?!VO-Ic)5-O=TyRY7y{tj;rzMqoMETm2H}AaWaO_IG7r-cyjlBEt>`Hsw6om z-*AWW$OVMR3v&y<%G+^a%(#wNZ{ z+Es_}kiv%Q5MC-d6c$v2(7y(R*UFk25PYjcaBzk2Rta#0kWFDPh4+e76T<2m5F%d5=bFHqN{jI&8+vmqby6?GCxgR_b?Ucn5^}&r zSzr}AW~*fTpFf}P&|XT&$vG+{9RGFg(CGF%@l_wDtzckU2g82tzhra-t1m1ZN4dcM zgW7*MnQ<_6)R*;6G(81o{`{(Esiq*qa-&kQj-i=S?mNTa)Gk&-Km3mD zpMEO0y$ugik$QZ?|8|~#F7dCi#|=`_F7*pycpX|KECu_S7hFAX{72PwkX( zpA25{U%qM=dQ+z$iXWh9DKwj(5zw}MnIuW1p*{`ZwNPmMqpazw^5^>$_|1w%LgPCX zSU$dVrCXwD@w%TOG9$lv;H-(dr6M7}4)~0bxRwcxU+#S+H2%3Q3*`3}UkhyoG&)xh z;P*^<@g)sR$M2jiW+X1Ypn)$4P``1vREXi z0oN9x@k^4+RRv%1gNA?ne^YfUg|=O!pL6}EvUWY_FetY*Iz_C6e(p5nCIKb;DGz?|Dt|AQn3Y^zji0t)B3{${$ zUSzI}Fe~CbxgfME2*2kH!*x+;RS}L8<9xZ3GKBUP8hf)ba7}1AB6AaHX+rxTG=7b+JHlKoe4_}X-2qR8d3_P- zJP@vE5MTTLDnz`7P<6EY_~^aSoQfJ-m5W(eOCnn7q@&>jele}vAUHxLDIBHIhi zf^dw`jC{=l6Z!y0MP|Owgu&*(F`?xbS_^0q&^QrI(BQYOC18NY8DBu8YlU!mXq@o{ zMY`4q*AyDxk%FME4d>rWpdwIMh;0!b2Jk8(G+%_d_3|nzG`8^v&Ga(2(2T+!5Hg!&d`!V^h5YAM9$DsLgUN)WN4g>rG?fR;RQk~BeX8ilA-b9 z3t!keeuHz3(43&r|89WoZ|?9y80`fu-68&fgq+>wMCKj{^Sk7n-7e5rPEUZXmtPJLgX>6tI+r=8fNCPxE?gF z7FTF&Nk5>z(D@Zv(5wi5Vk9mzH1#*t!7xSxTrPZx4&y@r zzVVEghtNV1ZV9awxT(;>5dIAC@)X)ogh!}~_A(w8!wEeS;N- zFgFoiK0+IgF#lAQS9767BK(ceS_qAmvLRdrErrHP`Mq{d&{jg@9O9SlyK?+n3o#lZ zmjowX8=-Mxu|Q5d+uMOgAj|dx~@fsksDF}1BWs3$1Z7RZank^b6v}p*_ zX=;H&n~pFmP5=h0nlE1G0HY@=nFJ0J31=eAge-W7&}Jdr8|j$dDl|vlRd8)Cru>}W zu7!hyFdIV0rzp?z+nL=I1e1V;z#J=Z(cuH|B_%v2KL=g{JRb8n%;WDcfNxRav3Du399Rjg1J(l@fQ`Ub zfM2xv5BKEx2>b*nzycr?+sFM1otuZ6FKa69gX^76VHFe#FU#g=Gfi zkYv|Q+JQ8wK$_xGz^-ik0R#^Lhk+x&G2l3m4x9i^0;hp9z**o|;5@(y%1Qq{FcFvp z1Owav!vL<-{=fiWATS8vl5PN02Fe2!*hPO}bY25*fVaRqfCtuWAP4vWd;~rLpMgne z%Sg083Wx=GkR1;s0N(=>fl0t*;74EzFb&|FGkL%*2k_N15>Swb+d>G~14bYpz(cD9 z@Sxfnb{l}_PM$M60z6xG2D$(|Q+5No15E+G<%j>D`w(CNFc2671OgW^a+iVMfGfaN zAR`_>cxK!V>;QHGsX!X=1YJ}UNC5bnu_-_T@ICM?Fc#n~Jsdn72nE7`p#UG<)&lDQ zKCx{89w6;Xa20S>pa;U`d*VkgfQQe9Koj5_pd!%KpmZx_SKS~Pl(B{E%2$4bE-Vd{ z0d50)%j6Xx1GoW1>y%%RF8(sYd_(0CfJa6i5&4SHA%GRI2l&F#egI!c>I75-ssYsj zSD-df5GVvV0EGd*T=oSVe+9e--T?1_X8_Md-2JiJ*H(Aoa2UK%^2TTd1_L~sGy)m} zHGmuT%Dw`2&hZ;CJX--CA9-A?0#pU60el@%F`xv%m$BRd?g96Khrknnud$g2{0C5g zBw!)12;hnDXJ84C0xSbo0IPu208W3^b!!n=2doD+0-JzYz+_-5z!&(8SDKf!D-r)a zf&oAupfA9e4Dp3SR`?$bgaACmbpSd7en4k{XE>hO8UPJ}MnDt54DdYW2{-}Hz#Yt> zyTCo*0q{HU2zbn$?+F4=foH%A;1A#pa09pn>;iTJJb&@LwI4VD)Ix_(1Wy76Vk8Fv z;}GUs86N_CR(lMThgJco2=GG$erUiC33dXhhL%_x2>b%<2Kd0vXK_Az9{~8g&FAaG zz!8AY(8qw|Kss;&IH`;*V%IR9530Yzr-#63_%a5V4EzB62uuN{0@Hz6z&t<(+901h zU}$v_#^83%+EWr5f~5fNXDaDkP=bUu6Dd1 zg3SOkFbV0$0^b5Whw_BS6J0H!2CxR&I$%Ap0hj}AGjIzy0vrYQ0TThfT`CaZ+oORz015*|fX{I1E1*Nz0N4XOEAgTG6Yv?>i86Zw!+-!J^+El*T1ZqI z_y#Bj)B)Upsfb$uBmyOIdw2sa47dqeZT|YW8gz{%}d}l z@D{iU>;Z^;kKss<3I0*2W_dT2&g97=I?bg5-It6w2o#WGA2Y2$3agrK~ZwP+7`a*%f0KvUMye zvPX6rYxX6H$TpE}tYaU>I{e<}S+vN^_y2nR=kJRh=cr)Y!a3Jyqcq#D(Isje(FPEM`Gr(C>73M?6 z5pV!@LKu5*U4VPdbGdeMfQ4u#l;)nQyZN@r2PV&|Al4Ox$40bQFV={#1@C??2MoxY zAmug71~`U1KQrv{JQ}Gx(x!kL&=_b0Gz1y|^#K>a6}Sps2J>(k*J%Q%b(FFi-x=}| z@-ox3iWv3gsQ|ShKer98;Wt>;b)ODL_&rqNH+8KGZ9tI;qs;mm{ z3L-D`s&F1Lb+mXhpz`@4&%w3_z{<10o&YzTdxTYfmdSjoV!e=OrF{4rB!49)sEk~( zFMyqe{Aaq5?+^3?h63u2BnWw48HNCX07sDkU=YAGE>n3qZ={q3Mj*pXy#5VG%0fc` zmAN2+`Dw$z&oWr>h+K75MO1!%4g*-ZQNTzbf*VsSt6JypS#Bk`vCw>VxHnqB7~n=Y z&>umEQh>t%`}!eZ49YoQ1mJmqi5wwqz~+LG089mb1tNjTz!cyhZ~#~cFkdvlJo|y) zfMj46uou_^%mn5Gvw;}^%i%rKP9O@{0c-%a1H|LM5}9qlR$vW~1SA3*f%U*TU@fp3 zSOvrbaX>7v7?=jA%FRKZ6_^fiI0Kwk^8B0$@RD)?X*zHoNW(Mljd@C?;`tnx0T+QwKn8Fb zxB|2X4~OAv$X^9+01+H&vyk~6xCh(??f@LCZzIhHZUM~4|1s?)@B(-aJOlm&o&ryR z$G{`tA;A26bXf-s#53;zRs*~P_!Yn|Ai^jZ8D$IbeFrcEWkG-zc#Vo@0p1BrLOL61 zI8qTb0nh+Oz#EkP0~i5cfcL=Pz*~S9>%Wk`0|X`Ia_Qg6_=wCW-~+( z0%`!|0X~M51^5_J1}F`f0;Pa65Lyyx381+0tTtwbXDfh@G!{T*<+&2lia;Xj>XB9e z__z~csXTBY6S*=&%~wU9cmI4o;__+$m+@w@CQ?2_)dpC}Isl)o900!caswIyu7G;B z=X00pm`*(YE+}XOGzMBhD1*z~fhIsxpc&AO0U96VIs$x1>j3Cc=8cpOcb-5SpcUW& z@X@6`&=zP1xM1jbYwL^rCZvnezI0*N1qD1+x*{zDLIBbMKtG@_P!qI1NLlmlNZA>C zApHgC34FwJFQmNzf1p3Wa#%TQU@)Gekq$yS5Lkr#P^2L|{<%#!63-)mn`me_(ow(w zWMOPFW~>4%K;`+s9Dsuk?`mfuKNFY+u#c!`ANG&w zcy_z&AXyELMrti3ZrW zuj840c`=?B0>Qb<1vIe&18Q36xPsEFZBJWS%x`ir2{R0A2zwfakz{(Edcq<~j$Q0k{uGk^TlG1Bt)}U_G!K z{2P&O0$A2|APLw4YzEZjl$X@49Lcyqjbtiu8yNQhyMbN6PM{$KHvsAb++QwNQ>JsC z`S${99kop5WrdFbDZpW1zW`4@gv>!;A8`72f!b|ec&FT%DIO8Rp1J67sv!QqkZY03c8I47J3872C{(PflC0dTp36& z0$Y(!0@9H`52OJXfHHvE0Lx&0wc+czXxzBeFl1atzTR16xM6OH1@rjbLjESe0#u=r za#Xq=ZvDA)xn*xgHC`8(g>`-euznj+wjEIE{LFej1)c#+`!87=z@y4~g*x!$2q~Jf zJF6jp!#IZljx8LIIAn87;c&n)hU3Xcl)V8y0Plgnfp@@L;4k0=c=%aO|3Ur>@EPFU z9Oro|eG#h3h5YauP(%AD=4o@!&VH!k9S<{z`mM7I7y_{ob0A6cA}S#J5&ml*X;c@OK0(@Eh;-1oLH49 zDO^!u_oUBWcl6vyo^ad@4lI4x$DAQpD|6VmV525bJAp(t8JJdzN4bep zbO8*`m%vaQ436)g_S~k~SR{wx=T-lpiY}1-9D=#3`OxAHj;lWeu##&3e8GSpH4NcI z(a4D6T|`G+Yg1XH179|mZtAo)2({RoVHI*5>&Vw55zdFFMNXft1C`LwW~x=l5X8 zYmvxCvlDJQRQY%m><$K)3#!2(cs#~sRWeQMUvI3`ReOUAW-Ik_6)i1eEakCI8BsIq zSwuT?Fw{3VI2xR2fxD>F^NUV)e{b7k36`nHnd}Ht!RfABlA$5I`I#lPX(&427boKz zik5o5w`R>V{1Pv=eH;Hk(6A3;S{a?t(H2+HL3pU6JFcjBQBT_;!1)$dU>=QUANt+u zV`l7xCKS64L7zCN{8_xRWw9yM9i+x3i+j>PXpGyoXateU%+kA7l0ICCoZ2)~*Y4t( z)~LW!1a`ojiv*{$|IpCjkxrqbYR(&Nt_w&=7Bn7}?Pj8r)cn6h2g;XGk>yg}A|`TUyIw5p86WZd|(DUctB|N-$QD zfk=5a>^9zF@S=6P;SQB4qNMDiL0 zo@$hWQv8vi4*j8KFmAiKJFjgXY=7Ocd7z+SQ*lV2L#qc!-RTpAN2;Z_v0kL8a5bT4c%%ccF~k0 z$L5e$33N7SjA>*u$6i}KB!!`oqmey{EyNYDZF~!Kc|;9)u35Sj6vRcVRgOQ$ZJT&G!_ zJfuS{(Ti6#=z2>yIh>}rhiIYG)|5N4xKH_}{ce`)K*K;Kc*Iwa zw5dBSpr0ui99RvbP#gd--y_Gq-g7;x>A^_?mT^aeD=1ks7gcp{z@P)e$I<~qzB-*> zCTWP(*v{xG9R-8t4rMW4UmJOB_TL&j$!hlqj!()&t4*a^L5F?yx?^^k_-^Ys^02aqJkq-9 zrCCVzT0@lzwz4^H^e?&P*Ytk7u`IIHv7iK#e`|!)cC?L??@_mX8`xGVv~(VaRgrzH zd&-MKvDwdSNov}&tuBDVGp?I&rdO{wXYb~8UB7*EPsYOF}t7LsGB zLtBtH&>%dS@mydp|5(C$Pg(a>uLO-XZEGtw()>o>j)VIYRcZ%w{oL0FV)}CcHlEd@ z$n7-=ZqP%q^e75JRb5*s%M8hzYCN8saV$;19t$BCW7?Tkw-bW|1nQ#g5oG$&oc2)c zGOcSbI=Y0QnmMZVyfr9zx})PBL4z^iQ84;(p8=~&0ugRYdLjl)rkbA6eGdKNiHJ{- z#Fh%&W%MBYiPdR2kg%jD^(h+s!khY(=m`)0QlGLtMNepgAK_Z!m*^!%A(3`oj=DJz z!`xd&(m6iQg6dme~Cz(cVyu}Lm0r|?VDC$ZR zy^+YvD{W^=3;Y2%Sj?n}Y_YDs=e+$*cSGUcO5e@tn>Sp=guFV4LArtNGGE;E11&cG zQ*u2#iz5^~YZUqRf&nJev|jMkZ{XuN)TQsUZ=a(5|CWYGS|bnA5FhB!il+Hsl{RZ3 zd%oLWM|Px|Iu8UNM@tMkFvEnxy;itIt>fvW z?1l<#TnfSWsgW;FRS&tU#pADr_VdF|N!m#xJ(PxlK{J6y_=%R3;0p_7&>^mKTd9-a zc-1?8-N*WeuBE7cgFIkr)`~4t2&JsiNXf-kNjlcMSZfQ9^J7JV^<>c=&E_+ zE|mwM@!T~{PM_moquAG;c6GsG)C>$f08NW$O?|&RIz+MvCL%5%NyF|oophY|k#kpQ zAp4-MYh&4is$|*ruGzZ^_f+wq{*=M&!Sp95VN|Fa8u`zmk_}@8!}viTp7j+9&7Rrl zc(KKjKK2}K2GQzn5ZRSVbQc}zMK_G9l()nVt*RfqTOMx|&cU!_E;j2fpL-G?!y3`m7?Krm#CmLt=D~ zzJcBO4H!72gr)ZUP;uiJEY-Xh#fHu3t3sLd_(mJw)8XZ03J1+AG`S~cK#R_@eXljF zV>2nO$x>-mkz874(A=XH|IXKzE`UKf9+J>YboyTdir%xUY_9{ZDJ}g+9H;|(Dc*>P z`l1&$+g+&&hduew%KlIrt18E!qh%Vs>*Klb9I7CA@-ogY?6P1HQR?< zxBMM^$|RN}sjgr_yn~m=KsfA2#rudB`cxeG*#kSRY8o*8ZpB-I#@XN~&BiN!TI`zS1<{r4`@y!s)E-%*oIcll7D91-LvdNBYqRX$dz6y=zZ zn?Wg3s>)Bg9RuXUQoPa3J%4VDnht;DlPh-JJ847!T2dNRf|e2oq*chgurvsH+m%l% z@+n2tmgWUQKUtp64u=Llm)!Vh*7KBKtqtZFOlh}hqzFnRKKA50?+B5Bv^5A5PgX~W z3ZySVm;^tD2`rS7TBU->ZeY&YOBOC{3!+I}su-c5vz4l~qOf{+%VRddW+255f*i#< z1=%294^-AXa+EfNW`oEE-BAxr1+UQ3j%ESH4;C$5?hlf~%~@|_>m#YA78o{OisAjw zK;eaQL+Xy!g--l)ObSHySoMtd4kptO=qw+ng|xxs9*j2c45qK!aIE<-SiatxK4`F6 zv1WU`QPJ6e{Sl%JWekTWRHX$WNE*Gxoe zme7Sn$W#>7?Fx}^%^rNU$~M_>IW|Y5eB%EH1@rY9e|0T)pM1!FXijGo6@|A$Y5UM0 z45oHKu|qypl-`9<1g^(?uu=9KwZA>OBJv`6!gWgu)?(FgY|0 zTQ>FaTB{@K2@vP8mNX&)6)eK&&N#Fsi__Nue;IgwN%xqiy78U-;4XYp!{XdHEG8Vm zqCFVOgQ2(golZ}DYc&G{2MY-77e?F1qv>H`WjAHqDLl_;25X%) zhjbNi4-`{SZgy+1WnR5~SiMzc2aT#XG9V~mOmeF=v1e?Y+bLRNXZa?KR*i-h=#gQZ1d#@j(U`kIru1FKb&HJ zMgN+IQ{yq<>;TSk(5h-gtJ;4(tIXSQ?AO?Y0pT=!j94}T;UFALd}bfNrb9dbt!aFW zQew|EP|AX`@y(bSe#@%hat{=~dp24Q3SW&6cb~BNNJOKON*$=b6O;;|Sk!n_B|Cb# zx;F(S4HO>F%TGsNzh9xlHm=hc_J!rMK`IZDc{AtcVaG0HDdM2qJB2cN?eQ|dYv(r3 zp%foY?qgvx7}9FA+=Exe%MTuS>64ejgl^UwO$R6ahwrgt;|~fR9xJ*CvmkVOZpX0D z^;5j!**3S;=6kxRR~iV-vY)E%UVu+Q{{lTmy1&iq?Wz>TbDhVGm818og-0Zab#9E0Wouc#V14(x<{b+3jc7yZL2_CP6l1ul6%{}0*SO}(9 z)DYAulUFSoFhQ&!IFF~u32G3q)W04t&jKUYx8Vt`=Zw!Ww>+6FT)u#V9jENPF;%|a zIG>%v(SL%x&^`6vTF5PQ{goU=f+vuEB7AltICv(BT}ID-7^COYKf5D_S)L>o`nigX zRm+OHRN5EyQsKae$n8rrN*zgzfs*ATm=wk=)nT?m$xk{1%SchlONkX0`k&8B#XN%I zY`A@%I~EZ#Z++d*>;JzoS}O7JUj@RaE%ApX5viq>4;Sd=T|tcGi8*c1<hn?GH>7sam_IDo-Zl$GFzbxlwd5b{|;UZT`q$dje4 z7G5H^L_Sk7PpVF%;iuGjlFI_>A_Xo8;D973 zi>aV2e|#+^_n2KlC0fs<$XQ@^m`M|6B5gI3VrGh-`e&AMCp?b#?|;7LU;LgMuh)22 zo3Dm`+Dv)v3#s+#m3>-myyC$L9=!NacP4p4wthW0cxzoOJSgJI?XPvg;R0DOh$73y zc(xqr+C1C6rsvZQ2%CJk$NC2jIZ9Rc53}|eF>)p9^5z739G*?-Ed9s2(#-%W8_y|Brjk}TX;;`<;_Si{Y8R!^T&;{5^CIXF zzOkD}ub9hhK2?i?mAlWEm+G~3vgd@gt<8HD<-$ZCO;J&pdJfU@UMcBNpXU=j;@9Qe z6*83`Q+UBU(LK`=WrM=qQ2m8v0fzaW_GVgxpwp6n&mkhjX~kN zuyb8w&R@!$(#M?LOB%GRF|-wRbq``>-Io@_y}qjh6-jt%w%AT$Y2({TSPKf4eqK26RR1u8E+!`Nt{h!;h$i<%P*b|c zl(~O)+X-&T^UG4gBGF3sbh$h-Zw<9dd|5N#3yi|y1qRNhtVNg~AD7eLi||@|Z7hvh zjDWE#mQF1e1M$bd>n*{h!M9j>FBRv~zr&6bL7|fQacPL?uu>kn*RQIlBsjX9SIiB` zzAI_M62#M4aTK!zA{WNdA4^0Bm(_9dd^SCibm90v^bhW5`7I)9Yz2jHLgz1QJ@Ab# z(H0cGQG$VzsXI;4lM+?r;gW=Wi$B z5(963q@KQsqjZ+>1sv>3d%JWm|Cd{-LsI*2M11ERPXa;4&+qN%Er@RaN;s| zCE-1tNdgUBijZfuRP(?YAGZyN|2{Oabf56k-x0RUr>}B z9c_c7$udZkYFVlh)fB}k%PzlLit))txyu{HKDPKOtM@tox9W&G7;RoJ zTi<-lBwe*tcW|o$>q~3Iw2fr50x}nFq*g01#+I98J$)txAH2C^*A~c7zA{>kV=r63 z*6Zw-qsqVHgC36$6s@+2wnB!BJ?gR-T=j0X;m`SZouu|9j)tH}fzbF#jdtFtcwefn zgsnEw7qqLcJwnG#)Gii2*J(2?jTHlhJDX!xvR7{*@0FN9XDMi<=*X*LEFSg8lH?Z4 zE$&`?)Qr$va?d5vMXvaJ5?RHee-DzVK^#UYiiX5tMzadEdT3&^TD^}S z4!xA6k^kUJc~G_tv)>*3qJLbD#)Du_5KJj|$ zq+hvHHtglhD6 z;ABcokUi!ro}GX0F|ohN>q*M|n4;V2KAR;NH$h2nSR|6#uMvavS=RFM@9MEIE_S~S7_;L;0{Z0m1l(t1A~7pU*g>-9OG1uy@Ta7^}v^g$Cd;y*pWlo6+-&8 zSQoSQ$*X7)F->I|)sGBJmv zDpgvCcLpKDWXI{*Yx(51W?e7K3>apk`ik)D145shm%eI}Q?&twa8*w*u;$+y**w@h z*3VgH;8kXTQZ?H4P?T4TuXs-X@ykFP5X5IC54uc!LWZ6+*V1F)B zJqA=h&llxxp_xq&Y5>RG*>&3kK{@1j@#;{dDI z+C}zL_67{29*XfdH$9CumHPN`{$xxQMfJRw#PXf0FknCR-G~V%U#e>4yImn|KW#;+ zdY`Rc;pWv%r3y;Zc`t2sKRSh~NWP}!8)3O=M}2>9Iq-=uS`4jOv`kAu!+US`GR3g^ zA3Z`9ocG3=b|>cC!e{NHc}eJJffwBWscQjVsJ5vXE_WyJ9wDFo^4_j1?V^g6aaeM-A8t4zPI>Q+a{X9vy?$~TdCjbZhh7)Vw-#i#OTEap^k7j{?b ziL>i2(MfPUMp3)4{@GK?F05)wD>#Fc*p2lzj%x14GAMtI@%=LuOPaSETYjk>^CB+1 zua*1Z$=`X}?D^@c$Vb}G$Ehzkgt8}S+#d8xsX=%4;NoDys=xQWDAmU2+jiue#xGN#r<5xqog0;^!iUqeH~9wx z3kT28^xwqg!l1Kcy$=nFsWf~a=JP_DwGSrMrP5)345w@R#K}U9RO+!`4Ai@(%HJzb zF4OmN@xgyPLIs=EBaluDwl_yN7j4@K~6{Njk^)za85V~T=7jqE9 zFVm_>Tcd$#auXXjtQz*BrYR(-yKa0D@%11yOZ6k4!$|S@LHZ%2_~IZA&otl=#!&tE zK_)unV{%X{>tFYf6*azdb5m0AnAZGVp1mu-)X6LMdksaB16ier6=wJ%`x6%c9k6N!=w-UcBX_%te0Na9q3-k&yghd%t?FepUR%Xb0H1G&W=qHx{ z1-pFZi}Z~d6a@~PdUhNa&8($Ewb764P)-_l&&yQus66bojzX|yrtG6rI~Wgb{OhtF zd_)4NbgMQdkno8lu3(`D&KMnVVQJ~i&th)@zXHWj~8)#2Y?|mnx07mj)OBglN$5Q zs?8+6=?8(r2Jv!p2PUJ^{&oS7fvG>%L*~_J{NF8il`k z1)mWPp0Ov`4mqk`Jb~$z>zP%j-%er)mA^ryXD1QLWTh<>mA=m#z0-9$RE&Rn)iq-C za6fKJIs_ZJU8l9D(22aFEfh(Ca;GdQ>a34aP%Jj(VOE?Z|LKw4%f_Vg*Tb-VbT@KOPU@P&l1B z86{`Yoim~%%{`5k1LM2#G_D+E3;b^_52P|@VYIx9nfet#{#6Vc_w8pf4*%0 z6?(gOxiY^o8*qOccMh^-8CX?s%d_L~!>b2;H?G9U^Vy8wRHxpip=sd!{Wi@^L#xU& zbxcD9%TH7Sdal*~Wt!+%^g91pCH!|im2A$7q4?*FSD(kvP-j<{J$uRCirdT0*j{~! z@;r9m-detCudc7cGY4qz=H1dq9&??)O`$h1aZO0r>|xli(6`?jZPu)%?(A7Smjr*X zb#%E&M~5U_!*dxt(~KkQ&g`&He}ZQ|N+e!-5tr1bj`fjmDB$x{+LPPI#s@7*HOI&J zyi|4$?A){H)ZND_l7G5bNn=Elk(4fu*~~6`_s^65Au}va52YO_jtFZdA6*iz?J?bP zSwATX&wQ1#AZy=pee5iA!ZQb+=bMeoj0kz~IT6piqCV=FdU|k{$!K$2y|CChll+=4 zs=98Z6`r{l-(u4ZFQYAA+bHyufbCTZpZnvLi$cGD$A8|wCV_Q#v_t_%lKa;>AM^=~ z3iiRXDW2C=T2g3gZI98$=Va@T*+Szki0;P2NA|M~4Hy+l`!0x%qO-w;US1HJ(x%y3 zT^V;KhWLjLw5=y4^_<9ew6-eEy(k72;iwuKG>$6163Zu7&Jh19MP;vxm8tq2v2t>! zyW;C2el3en&SXZlYOm6s2T&%@Et(TDnrC)s%hYGazIkJ01i!gOSawoLNy zYTA;TwH5IdO*3b0H8Sg{T_g34#xI4Yk2`9Y33RlJ zc84TH>RL=!?I}%io9^0uMQPMVh}#yRHA${BK)XVVmQM}TE~<0W_UTdAaGFE#)qj5;?9;f|FOJzo* zXy_U!plOh7yk1+mFbONP*3@o`Hi^vc!iQW$tpzzopmXJuwEh~pu|?Y?dGuE8TT!-n f)J|=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { console2 } from "forge-std/src/console2.sol"; -import { LibString } from "solady/src/utils/LibString.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; @@ -18,8 +17,6 @@ import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol" /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test { - using LibString for string; - address internal constant LOCKUP_DYNAMIC = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; uint256 internal defaultStreamId; @@ -40,7 +37,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ modifier givenNFTExists() { defaultStreamId = createDefaultStream(); - vm.warp({ timestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); _; } @@ -49,7 +46,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ /// 2. Remember to escape the EOL character \n with \\n. function test_TokenURI_Decoded() external skipOnMismatch givenNFTExists { string memory tokenURI = lockupDynamic.tokenURI(defaultStreamId); - tokenURI = tokenURI.replace({ search: "data:application/json;base64,", replacement: "" }); + tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Dynamic contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Dynamic Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Dynamic #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; diff --git a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol index 66290ad29..2362e29d9 100644 --- a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -24,7 +24,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); @@ -42,7 +42,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is givenStartTimeInThePast { // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); @@ -64,7 +64,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is whenWithWithdrawals { // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 4f90ab135..16e46c75f 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -166,7 +166,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenEndTimeInTheFuture { uint40 endTime = defaults.END_TIME(); - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); createDefaultStream(); } diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol index 0524c819c..6c4b0a5fb 100644 --- a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -25,7 +25,7 @@ contract GetStream_LockupLinear_Integration_Concrete_Test is LockupLinear_Integr } function test_GetStream_StatusSettled() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(defaultStreamId); LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); expectedStream.isCancelable = false; diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index e81d2a1ab..a49582dcc 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -19,6 +19,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is function test_StreamedAmountOf_CliffTimeInThePast() external + view givenNotNull givenStreamHasNotBeenCanceled givenStatusStreaming @@ -34,7 +35,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); @@ -46,7 +47,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 2600e18; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol index ac8eafa30..30aa29f37 100644 --- a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { console2 } from "forge-std/src/console2.sol"; -import { LibString } from "solady/src/utils/LibString.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; @@ -18,8 +17,6 @@ import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test { - using LibString for string; - address internal constant LOCKUP_LINEAR = 0x3381cD18e2Fb4dB236BF0525938AB6E43Db0440f; uint256 internal defaultStreamId; @@ -40,7 +37,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra modifier givenNFTExists() { defaultStreamId = createDefaultStream(); - vm.warp({ timestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); _; } @@ -49,7 +46,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra /// 2. Remember to escape the EOL character \n with \\n. function test_TokenURI_Decoded() external skipOnMismatch givenNFTExists { string memory tokenURI = lockupLinear.tokenURI(defaultStreamId); - tokenURI = tokenURI.replace({ search: "data:application/json;base64,", replacement: "" }); + tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Linear contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Linear Address: 0x3381cd18e2fb4db236bf0525938ab6e43db0440f\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Linear #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCgxOSwyMiUsNjMlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMTksMjIlLDYzJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woMTksMjIlLDYzJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBMaW5lYXI8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iMCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MzM4MWNkMThlMmZiNGRiMjM2YmYwNTI1OTM4YWI2ZTQzZGIwNDQwZiDigKIgU2FibGllciBWMiBMb2NrdXAgTGluZWFyPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9Ii01MCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYiDigKIgREFJPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjwvdGV4dD48dXNlIGhyZWY9IiNHbG93IiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjR2xvdyIgeD0iMTAwMCIgeT0iMTAwMCIgZmlsbC1vcGFjaXR5PSIuOSIvPjx1c2UgaHJlZj0iI0xvZ28iIHg9IjE3MCIgeT0iMTcwIiB0cmFuc2Zvcm09InNjYWxlKC42KSIvPjx1c2UgaHJlZj0iI0hvdXJnbGFzcyIgeD0iMTUwIiB5PSI5MCIgdHJhbnNmb3JtPSJyb3RhdGUoMTApIiB0cmFuc2Zvcm0tb3JpZ2luPSI1MDAgNTAwIi8+PHVzZSBocmVmPSIjUHJvZ3Jlc3MiIHg9IjE0NCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjU3RhdHVzIiB4PSIzNjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0Ftb3VudCIgeD0iNTY4IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNEdXJhdGlvbiIgeD0iNzA0IiB5PSI3OTAiLz48L3N2Zz4="}'; diff --git a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol index 326d29c31..c5a6d9d44 100644 --- a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -30,7 +30,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test is } modifier givenCliffTimeNotInTheFuture() { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); _; } diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 09f7524ad..29a12979a 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -200,7 +200,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered { uint40 endTime = defaults.END_TIME(); - vm.warp({ timestamp: endTime }); + vm.warp({ newTimestamp: endTime }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); createDefaultStream(); } @@ -219,7 +219,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenEndTimeInTheFuture { UD60x18 brokerFee = ZERO; - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); @@ -281,7 +281,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is { address nonContract = address(8128); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Run the test. vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol index 63e0d9742..3c9870943 100644 --- a/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol +++ b/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol @@ -25,7 +25,7 @@ contract GetStream_LockupTranched_Integration_Concrete_Test is LockupTranched_In } function test_GetStream_StatusSettled() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(defaultStreamId); LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); expectedStream.isCancelable = false; diff --git a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol index a1ae2ed26..cd145d590 100644 --- a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol @@ -23,7 +23,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: 0 }); + vm.warp({ newTimestamp: 0 }); uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); @@ -35,7 +35,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); @@ -54,7 +54,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is whenStartTimeInThePast { // Warp 1 second to the future. - vm.warp({ timestamp: defaults.START_TIME() + 1 seconds }); + vm.warp({ newTimestamp: defaults.START_TIME() + 1 seconds }); // Run the test. uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); @@ -75,7 +75,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is givenMultipleTranches givenCurrentTimestampNot1st { - vm.warp({ timestamp: defaults.END_TIME() - 1 seconds }); + vm.warp({ newTimestamp: defaults.END_TIME() - 1 seconds }); // Run the test. uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol index 033cfedb1..28e0257ad 100644 --- a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { console2 } from "forge-std/src/console2.sol"; -import { LibString } from "solady/src/utils/LibString.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; @@ -18,8 +17,6 @@ import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.so /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { - using LibString for string; - address internal constant LOCKUP_TRANCHED = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; uint256 internal defaultStreamId; @@ -40,7 +37,7 @@ contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Int modifier givenNFTExists() { defaultStreamId = createDefaultStream(); - vm.warp({ timestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); _; } @@ -49,7 +46,7 @@ contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Int /// 2. Remember to escape the EOL character \n with \\n. function test_TokenURI_Decoded() external skipOnMismatch givenNFTExists { string memory tokenURI = lockupTranched.tokenURI(defaultStreamId); - tokenURI = tokenURI.replace({ search: "data:application/json;base64,", replacement: "" }); + tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Tranched contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; diff --git a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol index 1867a4e06..0f1ea9bd2 100644 --- a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -24,7 +24,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is givenStreamHasNotBeenCanceled givenStatusStreaming { - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); @@ -42,7 +42,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is givenStartTimeInThePast { // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); @@ -63,7 +63,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is whenWithWithdrawals { // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); + vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Make the withdrawal. lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); diff --git a/test/integration/concrete/lockup/burn/burn.t.sol b/test/integration/concrete/lockup/burn/burn.t.sol index 0e98fb24b..f16ffa248 100644 --- a/test/integration/concrete/lockup/burn/burn.t.sol +++ b/test/integration/concrete/lockup/burn/burn.t.sol @@ -18,7 +18,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int notTransferableStreamId = createDefaultStreamNotTransferable(); // Make the Recipient (owner of the NFT) the caller in this test suite. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } function test_RevertWhen_DelegateCalled() external { @@ -51,7 +51,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenNotNull givenStreamHasNotBeenDepleted { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -62,7 +62,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenNotNull givenStreamHasNotBeenDepleted { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -73,7 +73,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenNotNull givenStreamHasNotBeenDepleted { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -84,16 +84,16 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenNotNull givenStreamHasNotBeenDepleted { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); - changePrank({ msgSender: users.sender }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + resetPrank({ msgSender: users.sender }); lockup.cancel(streamId); - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } modifier givenStreamHasBeenDepleted(uint256 streamId_) { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: streamId_, to: users.recipient }); _; } @@ -104,7 +104,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenNotNull givenStreamHasBeenDepleted(streamId) { - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, streamId, users.eve)); lockup.burn(streamId); } @@ -165,7 +165,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int lockup.approve({ to: users.operator, tokenId: streamId }); // Make the approved operator the caller in this test. - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index dbb24c005..e0f601a1d 100644 --- a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -42,14 +42,14 @@ abstract contract CancelMultiple_Integration_Concrete_Test is } function test_RevertGiven_AllStreamsCold() external whenNotDelegateCalled whenArrayCountNotZero givenNoNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, testStreamIds[0])); lockup.cancelMultiple({ streamIds: testStreamIds }); } function test_RevertGiven_SomeStreamsCold() external whenNotDelegateCalled whenArrayCountNotZero givenNoNull { uint256 earlyStreamId = createDefaultStreamWithEndTime({ endTime: defaults.CLIFF_TIME() + 1 seconds }); - vm.warp({ timestamp: defaults.CLIFF_TIME() + 1 seconds }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 1 seconds }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, earlyStreamId)); lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], earlyStreamId) }); } @@ -63,7 +63,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Run the test. vm.expectRevert( @@ -81,7 +81,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( @@ -98,7 +98,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is givenAllStreamsWarm whenCallerUnauthorized { - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Create a stream with Eve as the stream's sender. uint256 eveStreamId = createDefaultStreamWithSender(users.eve); @@ -120,7 +120,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( @@ -168,7 +168,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is givenAllStreamsCancelable { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Expect the assets to be refunded to the stream's sender. uint128 senderAmount0 = lockup.refundableAmountOf(testStreamIds[0]); diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/integration/concrete/lockup/cancel/cancel.t.sol index f77ec8659..6566400ff 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/integration/concrete/lockup/cancel/cancel.t.sol @@ -28,21 +28,21 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I } function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenNotNull givenStreamCold { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } function test_RevertGiven_StatusCanceled() external whenNotDelegateCalled givenNotNull givenStreamCold { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamCanceled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } function test_RevertGiven_StatusSettled() external whenNotDelegateCalled givenNotNull givenStreamCold { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } @@ -55,7 +55,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerUnauthorized { // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Run the test. vm.expectRevert( @@ -72,7 +72,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerUnauthorized { // Make the Recipient the caller in this test. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( @@ -95,7 +95,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I function test_Cancel_StatusPending() external { // Warp to the past. - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); // Cancel the stream. lockup.cancel(defaultStreamId); diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol index af633fb63..8bfcd06ae 100644 --- a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol @@ -25,10 +25,10 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo function test_RevertGiven_NFTBurned() external { // Simulate the passage of time. - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the Recipient the caller. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Deplete the stream. lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); @@ -45,7 +45,7 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo _; } - function test_GetRecipient() external givenNotNull givenNFTNotBurned { + function test_GetRecipient() external view givenNotNull givenNFTNotBurned { address actualRecipient = lockup.getRecipient(defaultStreamId); address expectedRecipient = users.recipient; assertEq(actualRecipient, expectedRecipient, "recipient"); diff --git a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index fcfecae3d..c35abea37 100644 --- a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -31,7 +31,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); @@ -43,7 +43,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); @@ -56,28 +56,28 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes } function test_GetRefundedAmount_StatusPending() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); } function test_GetRefundedAmount_StatusStreaming() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); } function test_GetRefundedAmount_StatusSettled() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); } function test_GetRefundedAmount_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; diff --git a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index 2558ae6e9..d7cc37828 100644 --- a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -22,7 +22,7 @@ abstract contract GetWithdrawnAmount_Integration_Concrete_Test is function test_GetWithdrawnAmount_NoPreviousWithdrawals() external givenNotNull { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -32,7 +32,7 @@ abstract contract GetWithdrawnAmount_Integration_Concrete_Test is function test_GetWithdrawnAmount() external givenNotNull givenPreviousWithdrawals { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Set the withdraw amount to the streamed amount. uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); diff --git a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol index 27752ddf2..5f0bf9c48 100644 --- a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol @@ -23,7 +23,7 @@ abstract contract IsCancelable_Integration_Concrete_Test is Integration_Test, Lo } function test_IsCancelable_Cold() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); // settled status + vm.warp({ newTimestamp: defaults.END_TIME() }); // settled status bool isCancelable = lockup.isCancelable(defaultStreamId); assertFalse(isCancelable, "isCancelable"); } diff --git a/test/integration/concrete/lockup/is-cold/isCold.t.sol b/test/integration/concrete/lockup/is-cold/isCold.t.sol index 84c4bbbbb..ebb99badb 100644 --- a/test/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/integration/concrete/lockup/is-cold/isCold.t.sol @@ -23,32 +23,32 @@ abstract contract IsCold_Integration_Concrete_Test is Integration_Test, Lockup_I } function test_IsCold_StatusPending() external givenNotNull { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); bool isCold = lockup.isCold(defaultStreamId); assertFalse(isCold, "isCold"); } function test_IsCold_StatusStreaming() external givenNotNull { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); bool isCold = lockup.isCold(defaultStreamId); assertFalse(isCold, "isCold"); } function test_IsCold_StatusSettled() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); bool isCold = lockup.isCold(defaultStreamId); assertTrue(isCold, "isCold"); } function test_IsCold_StatusCanceled() external givenNotNull { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); bool isCold = lockup.isCold(defaultStreamId); assertTrue(isCold, "isCold"); } function test_IsCold_StatusDepleted() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); bool isCold = lockup.isCold(defaultStreamId); assertTrue(isCold, "isCold"); diff --git a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 08cd3b2ad..0ba5d78c6 100644 --- a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -28,7 +28,7 @@ abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test, Lock } modifier givenStreamDepleted() { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); _; } diff --git a/test/integration/concrete/lockup/is-stream/isStream.t.sol b/test/integration/concrete/lockup/is-stream/isStream.t.sol index 82529686f..ac4f349a2 100644 --- a/test/integration/concrete/lockup/is-stream/isStream.t.sol +++ b/test/integration/concrete/lockup/is-stream/isStream.t.sol @@ -9,7 +9,7 @@ abstract contract IsStream_Integration_Concrete_Test is Integration_Test, Lockup function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { } - function test_IsStream_Null() external { + function test_IsStream_Null() external view { uint256 nullStreamId = 1729; bool isStream = lockup.isStream(nullStreamId); assertFalse(isStream, "isStream"); diff --git a/test/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/integration/concrete/lockup/is-warm/isWarm.t.sol index 3ab67548f..e784adc4c 100644 --- a/test/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -23,32 +23,32 @@ abstract contract IsWarm_Integration_Concrete_Test is Integration_Test, Lockup_I } function test_IsWarm_StatusPending() external givenNotNull { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); bool isWarm = lockup.isWarm(defaultStreamId); assertTrue(isWarm, "isWarm"); } function test_IsWarm_StatusStreaming() external givenNotNull { - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); bool isWarm = lockup.isWarm(defaultStreamId); assertTrue(isWarm, "isWarm"); } function test_IsWarm_StatusSettled() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); bool isWarm = lockup.isWarm(defaultStreamId); assertFalse(isWarm, "isWarm"); } function test_IsWarm_StatusCanceled() external givenNotNull { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); bool isWarm = lockup.isWarm(defaultStreamId); assertFalse(isWarm, "isWarm"); } function test_IsWarm_StatusDepleted() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); bool isWarm = lockup.isWarm(defaultStreamId); assertFalse(isWarm, "isWarm"); diff --git a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index 1240e8045..698e03894 100644 --- a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -24,7 +24,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te function test_RefundableAmountOf_StreamNotCancelable() external givenNotNull { uint256 streamId = createDefaultStreamNotCancelable(); - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); uint128 actualRefundableAmount = lockup.refundableAmountOf(streamId); uint128 expectedRefundableAmount = 0; assertEq(actualRefundableAmount, expectedRefundableAmount, "refundableAmount"); @@ -44,7 +44,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedRefundableAmount = 0; @@ -58,10 +58,10 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.warp({ timestamp: defaults.CLIFF_TIME() + 10 seconds }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedRefundableAmount = 0; assertEq(actualRefundableAmount, expectedRefundableAmount, "refundableAmount"); @@ -77,7 +77,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualRefundableAmount, expectedReturnableAmount, "refundableAmount"); @@ -89,7 +89,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = defaults.REFUND_AMOUNT(); assertEq(actualRefundableAmount, expectedReturnableAmount, "refundableAmount"); @@ -101,7 +101,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = 0; assertEq(actualRefundableAmount, expectedReturnableAmount, "refundableAmount"); @@ -113,7 +113,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamIsCancelable givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = 0; diff --git a/test/integration/concrete/lockup/renounce/renounce.t.sol b/test/integration/concrete/lockup/renounce/renounce.t.sol index fda715ef4..00a2c5da3 100644 --- a/test/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/integration/concrete/lockup/renounce/renounce.t.sol @@ -40,37 +40,37 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup } function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenStreamCold { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } function test_RevertGiven_StatusCanceled() external whenNotDelegateCalled givenStreamCold { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamCanceled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } function test_RevertGiven_StatusSettled() external whenNotDelegateCalled givenStreamCold { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } /// @dev This modifier runs the test twice: once with a "PENDING" status, and once with a "STREAMING" status. modifier givenStreamWarm() { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); _; - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); defaultStreamId = createDefaultStream(); _; } function test_RevertWhen_CallerNotSender() external whenNotDelegateCalled givenStreamWarm { // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Run the test. vm.expectRevert( diff --git a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol index eb7892b66..2b1c52cf6 100644 --- a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol @@ -17,7 +17,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test function test_RevertWhen_CallerNotAdmin() external { // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Run the test. vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); @@ -26,7 +26,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test modifier whenCallerAdmin() { // Make the Admin the caller in the rest of this test suite. - changePrank({ msgSender: users.admin }); + resetPrank({ msgSender: users.admin }); _; } diff --git a/test/integration/concrete/lockup/status-of/statusOf.t.sol b/test/integration/concrete/lockup/status-of/statusOf.t.sol index d6e2a23a5..43b275e39 100644 --- a/test/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/integration/concrete/lockup/status-of/statusOf.t.sol @@ -24,7 +24,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup } function test_StatusOf_AssetsFullyWithdrawn() external givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.DEPLETED; @@ -36,7 +36,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup } function test_StatusOf_StreamCanceled() external givenNotNull givenAssetsNotFullyWithdrawn { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.CANCELED; @@ -53,7 +53,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup givenAssetsNotFullyWithdrawn givenStreamNotCanceled { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); @@ -70,7 +70,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup givenStreamNotCanceled givenStartTimeNotInTheFuture { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.SETTLED; assertEq(actualStatus, expectedStatus); @@ -88,7 +88,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup givenStartTimeNotInTheFuture givenRefundableAmountNotZero { - vm.warp({ timestamp: defaults.START_TIME() + 1 seconds }); + vm.warp({ newTimestamp: defaults.START_TIME() + 1 seconds }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); diff --git a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index 853e600ea..acf7d0f17 100644 --- a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -25,7 +25,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint256 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); @@ -38,31 +38,31 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.warp({ timestamp: defaults.CLIFF_TIME() + 10 seconds }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_StreamedAmountOf_StatusPending() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_StreamedAmountOf_StatusSettled() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_StreamedAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); diff --git a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 867480479..7a13c870f 100644 --- a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -8,7 +8,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } function test_RevertGiven_StreamNotTransferable() external { diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 3e96b4ab7..891b44457 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -29,7 +29,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertWhen_CallerNotCurrentRecipient() external whenNotDelegateCalled givenNotNull { // Make Eve the caller in this test. - changePrank({ msgSender: users.eve }); + resetPrank({ msgSender: users.eve }); // Run the test. vm.expectRevert( @@ -40,7 +40,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertGiven_NFTBurned() external whenNotDelegateCalled givenNotNull whenCallerCurrentRecipient { // Deplete the stream. - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Burn the NFT. @@ -60,7 +60,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is whenCallerCurrentRecipient givenNFTNotBurned { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -90,7 +90,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is givenStreamTransferable { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Get the withdraw amount. uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index 2719b7eff..be7b774bb 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -13,7 +13,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit function test_WithdrawMax_EndTimeNotInTheFuture() external { // Warp to the stream's end. - vm.warp({ timestamp: defaults.END_TIME() + 1 seconds }); + vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds }); // Expect the ERC-20 assets to be transferred to the Recipient. expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); @@ -52,7 +52,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit function test_WithdrawMax() external givenEndTimeInTheFuture { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Get the withdraw amount. uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index dc9c75832..fdc0347de 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -74,7 +74,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is uint256[] memory streamIds = Solarray.uint256s(testStreamIds[0], testStreamIds[1], nullStreamId); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Expect the relevant error to be thrown. vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); @@ -94,7 +94,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is uint128[] memory amounts = Solarray.uint128s(defaults.WITHDRAW_AMOUNT()); // Simulate the passage of time. - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); @@ -114,7 +114,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is givenNoNull { // Simulate the passage of time. - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); @@ -136,7 +136,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenToNonZeroAddress { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Run the test. uint128[] memory amounts = Solarray.uint128s(defaults.WITHDRAW_AMOUNT(), 0, 0); @@ -155,7 +155,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenNoAmountZero { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Run the test. uint128 withdrawableAmount = lockup.withdrawableAmountOf(testStreamIds[2]); @@ -180,14 +180,14 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is whenNoAmountOverdraws { // Simulate the passage of time. - vm.warp({ timestamp: earlyStopTime }); + vm.warp({ newTimestamp: earlyStopTime }); // Cancel the 3rd stream. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); lockup.cancel(testStreamIds[2]); // Run the test with the caller provided in {whenCallerAuthorizedAllStreams}. - changePrank({ msgSender: caller }); + resetPrank({ msgSender: caller }); // Expect the withdrawals to be made. expectCallToTransfer({ to: users.recipient, value: testAmounts[0] }); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 9e4b9002e..1a470c742 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -36,7 +36,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr } function test_RevertGiven_StreamDepleted() external whenNotDelegateCalled givenNotNull { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -90,7 +90,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr address unknownCaller = address(0xCAFE); // Make Eve the caller in this test. - changePrank({ msgSender: unknownCaller }); + resetPrank({ msgSender: unknownCaller }); // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -115,7 +115,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawalAddressNotRecipient { // Make the Sender the caller in this test. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -169,10 +169,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr lockup.approve({ to: users.operator, tokenId: defaultStreamId }); // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: users.operator, amount: defaults.WITHDRAW_AMOUNT() }); @@ -240,7 +240,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint256 streamId = createDefaultStreamWithSender(address(reentrantSender)); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Halve the withdraw amount so that the recipient can re-entry and make another withdrawal. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT() / 2; @@ -327,10 +327,10 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawalAddressIsRecipient { // Make the unknown address the caller in this test. - changePrank({ msgSender: address(0xCAFE) }); + resetPrank({ msgSender: address(0xCAFE) }); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); @@ -352,7 +352,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawalAddressIsRecipient { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); @@ -364,7 +364,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr } modifier whenCallerSender() { - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); _; } @@ -380,7 +380,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenCallerSender { // Warp to the stream's end. - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.DEPOSIT_AMOUNT() }); @@ -402,7 +402,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr modifier givenEndTimeInTheFuture() { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); _; } @@ -590,7 +590,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_Withdraw_CallerRecipient(uint256 streamId, address sender) internal { // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Set the withdraw amount to the default amount. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); diff --git a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index 7e6c4a099..7677fd2b2 100644 --- a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -25,7 +25,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint256 expectedWithdrawableAmount = defaults.CLIFF_AMOUNT(); @@ -38,31 +38,31 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is givenNotNull givenStreamHasBeenCanceled { - vm.warp({ timestamp: defaults.CLIFF_TIME() }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.warp({ timestamp: defaults.CLIFF_TIME() + 10 seconds }); + vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } function test_WithdrawableAmountOf_StatusPending() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: getBlockTimestamp() - 1 seconds }); + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } function test_WithdrawableAmountOf_StatusSettled() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } function test_WithdrawableAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { - vm.warp({ timestamp: defaults.END_TIME() }); + vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index 653a8d688..c643f5cf3 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Concrete_Test } from "./NFTDescriptor.t.sol"; contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { - function test_GenerateAccentColor() external { + function test_GenerateAccentColor() external view { // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); string memory expectedColor = "hsl(302,69%,44%)"; diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 2e22d6933..4d7e7e2e2 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -18,13 +18,13 @@ contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concre _; } - function test_MapSymbol_LockupDynamic() external givenKnownNFT { + function test_MapSymbol_LockupDynamic() external view givenKnownNFT { string memory actualStreamingModel = nftDescriptorMock.mapSymbol_(lockupDynamic); string memory expectedStreamingModel = "Lockup Dynamic"; assertEq(actualStreamingModel, expectedStreamingModel, "streamingModel"); } - function test_MapSymbol_LockupLinear() external givenKnownNFT { + function test_MapSymbol_LockupLinear() external view givenKnownNFT { string memory actualStreamingModel = nftDescriptorMock.mapSymbol_(lockupLinear); string memory expectedStreamingModel = "Lockup Linear"; assertEq(actualStreamingModel, expectedStreamingModel, "streamingModel"); diff --git a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol index e4cf67633..98bbd036b 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol @@ -4,14 +4,14 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; contract SafeAssetDecimals_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { - function test_SafeAssetDecimals_EOA() external { + function test_SafeAssetDecimals_EOA() external view { address eoa = vm.addr({ privateKey: 1 }); uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(eoa)); uint8 expectedDecimals = 0; assertEq(actualDecimals, expectedDecimals, "decimals"); } - function test_SafeAssetDecimals_DecimalsNotImplemented() external { + function test_SafeAssetDecimals_DecimalsNotImplemented() external view { uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(noop)); uint8 expectedDecimals = 0; assertEq(actualDecimals, expectedDecimals, "decimals"); @@ -21,7 +21,7 @@ contract SafeAssetDecimals_Integration_Concrete_Test is NFTDescriptor_Integratio _; } - function test_SafeAssetDecimals() external whenAssetDecimalsDefined { + function test_SafeAssetDecimals() external view whenAssetDecimalsDefined { uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(dai)); uint8 expectedDecimals = dai.decimals(); assertEq(actualDecimals, expectedDecimals, "decimals"); diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index 8d7d8e3eb..7524ae278 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -6,14 +6,14 @@ import { ERC20Bytes32 } from "../../../../mocks/erc20/ERC20Bytes32.sol"; import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { - function test_SafeAssetSymbol_EOA() external { + function test_SafeAssetSymbol_EOA() external view { address eoa = vm.addr({ privateKey: 1 }); string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(eoa)); string memory expectedSymbol = "ERC20"; assertEq(actualSymbol, expectedSymbol, "symbol"); } - function test_SafeAssetSymbol_SymbolNotImplemented() external { + function test_SafeAssetSymbol_SymbolNotImplemented() external view { string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(noop)); string memory expectedSymbol = "ERC20"; assertEq(actualSymbol, expectedSymbol, "symbol"); @@ -48,7 +48,7 @@ contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_ _; } - function test_SafeAssetSymbol() external whenERC20Contract givenSymbolString givenSymbolNotLong { + function test_SafeAssetSymbol() external view whenERC20Contract givenSymbolString givenSymbolNotLong { string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(dai)); string memory expectedSymbol = dai.symbol(); assertEq(actualSymbol, expectedSymbol, "symbol"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index cce900d40..22a98f8d2 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -101,7 +101,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); UD60x18 brokerFee = ZERO; - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); @@ -207,7 +207,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is }); // Make the fuzzed funder the caller in the rest of this test. - changePrank(funder); + resetPrank(funder); // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 140b4fec5..4ea56540c 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -19,7 +19,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test.setUp(); StreamedAmountOf_Integration_Shared_Test.setUp(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: @@ -58,7 +58,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); @@ -119,7 +119,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); @@ -166,16 +166,16 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Warp to the future for the first time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. uint128 streamedAmount0 = lockupDynamic.streamedAmountOf(streamId); // Warp to the future for the second time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp1 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. uint128 streamedAmount1 = lockupDynamic.streamedAmountOf(streamId); - assertGte(streamedAmount1, streamedAmount0, "streamedAmount"); + assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol index 576b359dc..10d3fc893 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -69,7 +69,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Make the Sender the caller. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Create the stream with the fuzzed segments. LockupDynamic.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLD(); @@ -79,7 +79,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is vars.streamId = lockupDynamic.createWithTimestamps(createParams); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + params.timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + params.timeJump }); // Query the withdrawable amount. vars.withdrawableAmount = lockupDynamic.withdrawableAmountOf(vars.streamId); @@ -102,7 +102,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is emit MetadataUpdate({ _tokenId: vars.streamId }); // Make the Recipient the caller. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 4bba84718..045ebc2c5 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -20,7 +20,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Fuzz_Test.setUp(); WithdrawableAmountOf_Integration_Shared_Test.setUp(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } modifier whenStartTimeInThePast() { @@ -46,7 +46,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); @@ -95,7 +95,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 9a92d315e..09ad044fa 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -128,7 +128,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.brokerFee; // Make the fuzzed funder the caller in this test. - changePrank(funder); + resetPrank(funder); // Mint enough assets to the funder. deal({ token: address(dai), to: funder, give: params.totalAmount }); diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 0397c9af8..c8f452713 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -21,7 +21,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is StreamedAmountOf_Integration_Shared_Test.setUp(); defaultStreamId = createDefaultStream(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } function testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40 timeJump) @@ -30,7 +30,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is givenStreamHasNotBeenCanceled { timeJump = boundUint40(timeJump, 0, defaults.CLIFF_DURATION() - 1); - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); @@ -71,7 +71,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); @@ -103,16 +103,16 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is uint256 streamId = lockupLinear.createWithTimestamps(params); // Warp to the future for the first time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. uint128 streamedAmount0 = lockupLinear.streamedAmountOf(streamId); // Warp to the future for the second time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp1 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. uint128 streamedAmount1 = lockupLinear.streamedAmountOf(streamId); - assertGte(streamedAmount1, streamedAmount0, "streamedAmount"); + assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 0c3c20b46..bdd34946c 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -27,14 +27,14 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is givenStreamHasNotBeenCanceled { timeJump = boundUint40(timeJump, 0, defaults.CLIFF_DURATION() - 1); - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } modifier whenCliffTimeNotInTheFuture() { - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); _; } @@ -68,7 +68,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); @@ -122,7 +122,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Make the withdrawal. lockupLinear.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 7d197ae39..251bbf1e7 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -101,7 +101,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); UD60x18 brokerFee = ZERO; - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); @@ -208,7 +208,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is }); // Make the fuzzed funder the caller in the rest of this test. - changePrank(funder); + resetPrank(funder); // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); diff --git a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 31b8a325f..35ab45655 100644 --- a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -19,7 +19,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Fuzz_Test.setUp(); StreamedAmountOf_Integration_Shared_Test.setUp(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } modifier givenMultipleTranches() { @@ -75,7 +75,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(streamId); @@ -122,16 +122,16 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is uint256 streamId = lockupTranched.createWithTimestamps(params); // Warp to the future for the first time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp0 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. uint128 streamedAmount0 = lockupTranched.streamedAmountOf(streamId); // Warp to the future for the second time. - vm.warp({ timestamp: defaults.START_TIME() + timeWarp1 }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. uint128 streamedAmount1 = lockupTranched.streamedAmountOf(streamId); - assertGte(streamedAmount1, streamedAmount0, "streamedAmount"); + assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/integration/fuzz/lockup-tranched/withdraw.t.sol index d278e8e40..7a73f5df6 100644 --- a/test/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -69,7 +69,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Make the Sender the caller. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); // Create the stream with the fuzzed tranches. LockupTranched.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLT(); @@ -79,7 +79,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is vars.streamId = lockupTranched.createWithTimestamps(createParams); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + params.timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + params.timeJump }); // Query the withdrawable amount. vars.withdrawableAmount = lockupTranched.withdrawableAmountOf(vars.streamId); @@ -93,7 +93,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); // Make the Recipient the caller. - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Expect the assets to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); diff --git a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 50f6367d2..35d86f64c 100644 --- a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -20,7 +20,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Fuzz_Test.setUp(); WithdrawableAmountOf_Integration_Shared_Test.setUp(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } modifier whenStartTimeInThePast() { @@ -46,7 +46,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is // Simulate the passage of time. uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); @@ -95,7 +95,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is uint256 streamId = lockupTranched.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ timestamp: currentTime }); + vm.warp({ newTimestamp: currentTime }); // Make the withdrawal. lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/integration/fuzz/lockup/cancel.t.sol index 165c4c8cd..c4188c082 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/integration/fuzz/lockup/cancel.t.sol @@ -22,7 +22,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ timeJump = _bound(timeJump, 1 seconds, 100 weeks); // Warp to the past. - vm.warp({ timestamp: getBlockTimestamp() - timeJump }); + vm.warp({ newTimestamp: getBlockTimestamp() - timeJump }); // Cancel the stream. lockup.cancel(defaultStreamId); @@ -63,7 +63,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. uint128 streamedAmount = lockup.streamedAmountOf(streamId); diff --git a/test/integration/fuzz/lockup/cancelMultiple.t.sol b/test/integration/fuzz/lockup/cancelMultiple.t.sol index 6e372b1ae..aac5f1d6c 100644 --- a/test/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/integration/fuzz/lockup/cancelMultiple.t.sol @@ -31,7 +31,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc uint256 streamId = createDefaultStreamWithEndTime(endTime); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Create the stream ids array. uint256[] memory streamIds = Solarray.uint256s(testStreamIds[0], streamId); diff --git a/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol index e19422335..71da96105 100644 --- a/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol +++ b/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol @@ -16,7 +16,7 @@ abstract contract GetWithdrawnAmount_Integration_Fuzz_Test is timeJump = _bound(timeJump, 0 seconds, defaults.TOTAL_DURATION() * 2); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -35,7 +35,7 @@ abstract contract GetWithdrawnAmount_Integration_Fuzz_Test is timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. uint128 streamedAmount = lockup.streamedAmountOf(defaultStreamId); diff --git a/test/integration/fuzz/lockup/refundableAmountOf.t.sol b/test/integration/fuzz/lockup/refundableAmountOf.t.sol index 92c635e9d..013548a9d 100644 --- a/test/integration/fuzz/lockup/refundableAmountOf.t.sol +++ b/test/integration/fuzz/lockup/refundableAmountOf.t.sol @@ -19,7 +19,7 @@ abstract contract RefundableAmountOf_Integration_Fuzz_Test is Integration_Test, timeJump = _bound(timeJump, 0 seconds, defaults.TOTAL_DURATION() * 2); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Get the streamed amount. uint128 streamedAmount = lockup.streamedAmountOf(defaultStreamId); diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/integration/fuzz/lockup/withdraw.t.sol index 8f591955e..fd4dbecd9 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/integration/fuzz/lockup/withdraw.t.sol @@ -25,10 +25,10 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I vm.assume(caller != users.sender && caller != users.recipient); // Make the fuzzed address the caller in this test. - changePrank({ msgSender: caller }); + resetPrank({ msgSender: caller }); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); @@ -62,10 +62,10 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I lockup.approve({ to: users.operator, tokenId: defaultStreamId }); // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); // Simulate the passage of time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. lockup.withdraw({ streamId: defaultStreamId, to: to, amount: defaults.WITHDRAW_AMOUNT() }); @@ -103,12 +103,12 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I vm.assume(to != address(0)); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Cancel the stream. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); lockup.cancel({ streamId: defaultStreamId }); - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); // Bound the withdraw amount. uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); @@ -170,7 +170,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I vm.assume(to != address(0)); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); diff --git a/test/integration/fuzz/lockup/withdrawMax.t.sol b/test/integration/fuzz/lockup/withdrawMax.t.sol index a9d8d5add..b15c2fb4a 100644 --- a/test/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/integration/fuzz/lockup/withdrawMax.t.sol @@ -15,7 +15,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra timeJump = _bound(timeJump, defaults.TOTAL_DURATION(), defaults.TOTAL_DURATION() * 2); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Expect the ERC-20 assets to be transferred to the Recipient. expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); @@ -56,7 +56,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Get the withdraw amount. uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); diff --git a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol index 198fa4e2d..ecde8780a 100644 --- a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol @@ -31,7 +31,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is timeJump = _bound(timeJump, 0, defaults.TOTAL_DURATION() * 2); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Get the withdraw amount. uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); diff --git a/test/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/integration/fuzz/lockup/withdrawMultiple.t.sol index 71f0a5ac1..fae6c0e43 100644 --- a/test/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -33,7 +33,7 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is timeJump = _bound(timeJump, defaults.TOTAL_DURATION(), defaults.TOTAL_DURATION() * 2 - 1 seconds); // Create a new stream with an end time double that of the default stream. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); uint40 ongoingEndTime = defaults.END_TIME() + defaults.TOTAL_DURATION(); uint256 ongoingStreamId = createDefaultStreamWithEndTime(ongoingEndTime); @@ -42,10 +42,10 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is uint128 settledWithdrawAmount = defaults.DEPOSIT_AMOUNT(); // Run the test with the caller provided in {whenCallerAuthorizedAllStreams}. - changePrank({ msgSender: caller }); + resetPrank({ msgSender: caller }); // Simulate the passage of time. - vm.warp({ timestamp: defaults.START_TIME() + timeJump }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the ongoing withdraw amount. uint128 ongoingWithdrawableAmount = lockup.withdrawableAmountOf(ongoingStreamId); diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index fc6153371..3d3b73633 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -25,7 +25,7 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { function setUp() public virtual override { // Make the Sender the default caller in this test suite. - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/integration/shared/lockup/cancel.t.sol b/test/integration/shared/lockup/cancel.t.sol index 7f6427184..9864b8455 100644 --- a/test/integration/shared/lockup/cancel.t.sol +++ b/test/integration/shared/lockup/cancel.t.sol @@ -8,7 +8,7 @@ abstract contract Cancel_Integration_Shared_Test is Lockup_Integration_Shared_Te function setUp() public virtual override { defaultStreamId = createDefaultStream(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); } modifier whenNotDelegateCalled() { @@ -43,7 +43,7 @@ abstract contract Cancel_Integration_Shared_Test is Lockup_Integration_Shared_Te /// contract, the streaming starts after the start time. modifier givenStatusStreaming() { // Warp to the future, after the stream's start time but before the stream's end time. - vm.warp({ timestamp: defaults.WARP_26_PERCENT() }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); _; } diff --git a/test/integration/shared/lockup/cancelMultiple.t.sol b/test/integration/shared/lockup/cancelMultiple.t.sol index 79f62047f..e0af37aa7 100644 --- a/test/integration/shared/lockup/cancelMultiple.t.sol +++ b/test/integration/shared/lockup/cancelMultiple.t.sol @@ -15,7 +15,7 @@ abstract contract CancelMultiple_Integration_Shared_Test is Lockup_Integration_S /// @dev Creates the default streams used throughout the tests. function createTestStreams() internal { // Warp back to the original timestamp. - vm.warp({ timestamp: originalTime }); + vm.warp({ newTimestamp: originalTime }); // Create the test streams. testStreamIds = new uint256[](2); @@ -46,9 +46,9 @@ abstract contract CancelMultiple_Integration_Shared_Test is Lockup_Integration_S modifier whenCallerAuthorizedAllStreams() { _; - vm.warp({ timestamp: originalTime }); + vm.warp({ newTimestamp: originalTime }); createTestStreams(); - changePrank({ msgSender: users.sender }); + resetPrank({ msgSender: users.sender }); _; } diff --git a/test/integration/shared/lockup/getWithdrawnAmount.t.sol b/test/integration/shared/lockup/getWithdrawnAmount.t.sol index 35bd18a30..e7a3985ca 100644 --- a/test/integration/shared/lockup/getWithdrawnAmount.t.sol +++ b/test/integration/shared/lockup/getWithdrawnAmount.t.sol @@ -7,7 +7,7 @@ abstract contract GetWithdrawnAmount_Integration_Shared_Test is Lockup_Integrati uint256 internal defaultStreamId; function setUp() public virtual override { - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } modifier givenNotNull() { diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 69fc8cb11..ac9dcfced 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -8,7 +8,7 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } modifier whenNotDelegateCalled() { @@ -20,7 +20,7 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ } modifier givenStreamNotDepleted() { - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); _; } diff --git a/test/integration/shared/lockup/withdrawMax.t.sol b/test/integration/shared/lockup/withdrawMax.t.sol index f2b083058..f19c3323c 100644 --- a/test/integration/shared/lockup/withdrawMax.t.sol +++ b/test/integration/shared/lockup/withdrawMax.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMax_Integration_Shared_Test is Lockup_Integration_Shar function setUp() public virtual override { defaultStreamId = createDefaultStream(); - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } modifier givenEndTimeInTheFuture() { diff --git a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol index f332e3dde..218e8d3ce 100644 --- a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Shared_Test is Lockup_Integ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); } modifier whenNotDelegateCalled() { diff --git a/test/integration/shared/lockup/withdrawMultiple.t.sol b/test/integration/shared/lockup/withdrawMultiple.t.sol index a20815ae2..5b6e3ad9a 100644 --- a/test/integration/shared/lockup/withdrawMultiple.t.sol +++ b/test/integration/shared/lockup/withdrawMultiple.t.sol @@ -19,7 +19,7 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration /// @dev Creates the default streams used throughout the tests. function createTestStreams() internal { // Warp back to the original timestamp. - vm.warp({ timestamp: originalTime }); + vm.warp({ newTimestamp: originalTime }); // Define the default amounts. testAmounts = new uint128[](3); @@ -54,7 +54,7 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration } modifier givenNoDepletedStream() { - vm.warp({ timestamp: defaults.START_TIME() }); + vm.warp({ newTimestamp: defaults.START_TIME() }); _; } @@ -71,14 +71,14 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration _; createTestStreams(); caller = users.recipient; - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); _; createTestStreams(); caller = users.operator; - changePrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient }); lockup.setApprovalForAll({ operator: users.operator, approved: true }); caller = users.operator; - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); _; } diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index 8ec23a98d..bf44eabb5 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -52,7 +52,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { withdrawnAmountsSum += uint256(lockup.getWithdrawnAmount(streamId)); } - assertGte( + assertGe( contractBalance, depositedAmountsSum - refundedAmountsSum - withdrawnAmountsSum, unicode"Invariant violation: contract balances < Σ deposited amounts - Σ refunded amounts - Σ withdrawn amounts" @@ -63,7 +63,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( + assertGe( lockup.getDepositedAmount(streamId), lockup.streamedAmountOf(streamId), "Invariant violation: deposited amount < streamed amount" @@ -75,7 +75,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( + assertGe( lockup.getDepositedAmount(streamId), lockup.withdrawableAmountOf(streamId), "Invariant violation: deposited amount < withdrawable amount" @@ -87,7 +87,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( + assertGe( lockup.getDepositedAmount(streamId), lockup.getWithdrawnAmount(streamId), "Invariant violation: deposited amount < withdrawn amount" @@ -315,7 +315,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( + assertGe( lockup.streamedAmountOf(streamId), lockup.withdrawableAmountOf(streamId), "Invariant violation: streamed amount < withdrawable amount" @@ -327,7 +327,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGte( + assertGe( lockup.streamedAmountOf(streamId), lockup.getWithdrawnAmount(streamId), "Invariant violation: streamed amount < withdrawn amount" diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index ac99bfd53..048f0fa74 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -73,7 +73,7 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { } /// @dev Settled streams must not appear as cancelable in {SablierV2LockupDynamic.getStream}. - function invariant_StatusSettled_GetStream() external { + function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index bca4387eb..6c76c8d29 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { Lockup } from "src/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupLinearHandler } from "./handlers/LockupLinearHandler.sol"; @@ -87,7 +87,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { } /// @dev Settled streams must not appear as cancelable in {SablierV2LockupLinear.getStream}. - function invariant_StatusSettled_GetStream() external { + function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/LockupTranched.t.sol b/test/invariant/LockupTranched.t.sol index e076af08a..03f1d55ae 100644 --- a/test/invariant/LockupTranched.t.sol +++ b/test/invariant/LockupTranched.t.sol @@ -59,7 +59,7 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { //////////////////////////////////////////////////////////////////////////*/ /// @dev Settled streams must not appear as cancelable in {SablierV2LockupTranched.getStream}. - function invariant_StatusSettled_GetStream() external { + function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/handlers/BaseHandler.sol b/test/invariant/handlers/BaseHandler.sol index 2fc68c335..728809cb7 100644 --- a/test/invariant/handlers/BaseHandler.sol +++ b/test/invariant/handlers/BaseHandler.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Vm } from "@prb/test/src/PRBTest.sol"; import { StdCheats } from "forge-std/src/StdCheats.sol"; import { Constants } from "../../utils/Constants.sol"; @@ -18,9 +17,6 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev Maximum number of streams that can be created during an invariant campaign. uint256 internal constant MAX_STREAM_COUNT = 100; - /// @dev The virtual address of the Foundry VM. - address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - /// @dev Maps function names to the number of times they have been called. mapping(string func => uint256 calls) public calls; @@ -37,9 +33,6 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev Reference to the timestamp store, which is needed for simulating the passage of time. TimestampStore public timestampStore; - /// @dev An instance of the Foundry VM, which contains cheatcodes for testing. - Vm internal constant vm = Vm(VM_ADDRESS); - /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -87,7 +80,7 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev Makes the provided sender the caller. modifier useNewSender(address sender) { - changePrank(sender); + resetPrank(sender); _; } } diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index 94dc6a034..f137b6f39 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -49,7 +49,7 @@ abstract contract LockupHandler is BaseHandler { modifier useAdmin() { address admin = lockup.admin(); - changePrank(admin); + resetPrank(admin); _; } @@ -68,14 +68,14 @@ abstract contract LockupHandler is BaseHandler { modifier useFuzzedStreamRecipient() { uint256 lastStreamId = lockupStore.lastStreamId(); currentRecipient = lockupStore.recipients(currentStreamId); - changePrank(currentRecipient); + resetPrank(currentRecipient); _; } modifier useFuzzedStreamSender() { uint256 lastStreamId = lockupStore.lastStreamId(); currentSender = lockupStore.senders(currentStreamId); - changePrank(currentSender); + resetPrank(currentSender); _; } diff --git a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol b/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol index c8b27a5d8..253915466 100644 --- a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol +++ b/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol @@ -8,7 +8,7 @@ import { Adminable_Unit_Shared_Test } from "../../../shared/Adminable.t.sol"; contract TransferAdmin_Unit_Concrete_Test is Adminable_Unit_Shared_Test { function test_RevertWhen_CallerNotAdmin() external { // Make Eve the caller in this test. - changePrank(users.eve); + resetPrank(users.eve); // Run the test. vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); diff --git a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol b/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol index b01b1ba38..369c95d25 100644 --- a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol +++ b/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol @@ -14,7 +14,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test return string.concat(SVGElements.SIGN_GE, " ", abbreviation); } - function test_AbbreviateAmount_Zero() external { + function test_AbbreviateAmount_Zero() external view { string memory expectedAbbreviation = "0"; assertEq(aa({ amount: 0, decimals: 0 }), expectedAbbreviation, "abbreviation"); assertEq(aa({ amount: 0, decimals: 1 }), expectedAbbreviation, "abbreviation"); @@ -22,7 +22,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 0, decimals: 18 }), expectedAbbreviation, "abbreviation"); } - function test_AbbreviateAmount_Tiny() external { + function test_AbbreviateAmount_Tiny() external view { string memory expectedAbbreviation = string.concat(SVGElements.SIGN_LT, " 1"); assertEq(aa({ amount: 5, decimals: 1 }), expectedAbbreviation, "abbreviation"); assertEq(aa({ amount: 9, decimals: 1 }), expectedAbbreviation, "abbreviation"); @@ -32,7 +32,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 1e18 - 1, decimals: 18 }), expectedAbbreviation, "abbreviation"); } - function test_AbbreviateAmount_Zillions() external { + function test_AbbreviateAmount_Zillions() external view { string memory expectedAbbreviation = string.concat(SVGElements.SIGN_GT, " 999.99T"); assertEq(aa({ amount: 1e15, decimals: 0 }), expectedAbbreviation, "abbreviation"); assertEq(aa({ amount: 1e16, decimals: 1 }), expectedAbbreviation, "abbreviation"); @@ -44,7 +44,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: MAX_UINT128, decimals: 18 }), expectedAbbreviation, "abbreviation"); } - function test_AbbreviateAmount_NoSuffix() external { + function test_AbbreviateAmount_NoSuffix() external view { assertEq(aa({ amount: 1, decimals: 0 }), ge("1"), "abbreviation"); assertEq(aa({ amount: 5, decimals: 0 }), ge("5"), "abbreviation"); assertEq(aa({ amount: 121, decimals: 1 }), ge("12"), "abbreviation"); @@ -53,7 +53,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 988e18, decimals: 18 }), ge("988"), "abbreviation"); } - function test_AbbreviateAmount_Thousands() external { + function test_AbbreviateAmount_Thousands() external view { assertEq(aa({ amount: 1337, decimals: 0 }), ge("1.33K"), "abbreviation"); assertEq(aa({ amount: 1080, decimals: 0 }), ge("1.08K"), "abbreviation"); assertEq(aa({ amount: 1800, decimals: 0 }), ge("1.80K"), "abbreviation"); @@ -64,7 +64,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 201_287e18, decimals: 18 }), ge("201.28K"), "abbreviation"); } - function test_AbbreviateAmount_Millions() external { + function test_AbbreviateAmount_Millions() external view { assertEq(aa({ amount: 1_337_081, decimals: 0 }), ge("1.33M"), "abbreviation"); assertEq(aa({ amount: 2_194_000, decimals: 0 }), ge("2.19M"), "abbreviation"); assertEq(aa({ amount: 30_448_842, decimals: 1 }), ge("3.04M"), "abbreviation"); @@ -74,7 +74,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 577_308_003e18, decimals: 18 }), ge("577.30M"), "abbreviation"); } - function test_AbbreviateAmount_Billions() external { + function test_AbbreviateAmount_Billions() external view { assertEq(aa({ amount: 1_337_081_132, decimals: 0 }), ge("1.33B"), "abbreviation"); assertEq(aa({ amount: 2_763_455_030, decimals: 0 }), ge("2.76B"), "abbreviation"); assertEq(aa({ amount: 30_008_011_215, decimals: 1 }), ge("3B"), "abbreviation"); @@ -84,7 +84,7 @@ contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test assertEq(aa({ amount: 699_881_672_021e18, decimals: 18 }), ge("699.88B"), "abbreviation"); } - function test_AbbreviateAmount_Trillions() external { + function test_AbbreviateAmount_Trillions() external view { assertEq(aa({ amount: 2_578_924_152_034, decimals: 0 }), ge("2.57T"), "abbreviation"); assertEq(aa({ amount: 3_931_548_209_201, decimals: 0 }), ge("3.93T"), "abbreviation"); assertEq(aa({ amount: 60_008_233_054_613, decimals: 1 }), ge("6T"), "abbreviation"); diff --git a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol b/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol index 8d5cf0a2b..62cae342b 100644 --- a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol +++ b/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol @@ -6,7 +6,7 @@ import { SVGElements } from "src/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function test_CalculateDurationInDays_Zero() external { + function test_CalculateDurationInDays_Zero() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime + 1 days - 1 seconds; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); @@ -14,7 +14,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre assertEq(actualDurationInDays, expectedDurationInDays, "durationInDays"); } - function test_CalculateDurationInDays_One() external { + function test_CalculateDurationInDays_One() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime + 1 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); @@ -22,7 +22,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre assertEq(actualDurationInDays, expectedDurationInDays, "durationInDays"); } - function test_CalculateDurationInDays_FortyTwo() external { + function test_CalculateDurationInDays_FortyTwo() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime + 42 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); @@ -30,7 +30,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre assertEq(actualDurationInDays, expectedDurationInDays, "durationInDays"); } - function test_CalculateDurationInDays_Leet() external { + function test_CalculateDurationInDays_Leet() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime + 1337 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); @@ -38,7 +38,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre assertEq(actualDurationInDays, expectedDurationInDays, "durationInDays"); } - function test_CalculateDurationInDays_TenThousand() external { + function test_CalculateDurationInDays_TenThousand() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime + 10_000 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); @@ -46,7 +46,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre assertEq(actualDurationInDays, expectedDurationInDays, "durationInDays"); } - function test_CalculateDurationInDays_Overflow() external { + function test_CalculateDurationInDays_Overflow() external view { uint256 startTime = block.timestamp; uint256 endTime = startTime - 1 seconds; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); diff --git a/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol b/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol index ec70b8394..a01fd49ea 100644 --- a/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol +++ b/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol @@ -19,13 +19,13 @@ contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T return bytes(text).length * CHAR_WIDTH_SMALL; } - function test_CalculatePixelWidth_EmptyString() external { + function test_CalculatePixelWidth_EmptyString() external view { uint256 actualWidth = cpw({ text: "", largeFont: false }); uint256 expectedWidth = 0; assertEq(actualWidth, expectedWidth, "width"); } - function test_CalculatePixelWidth_Caption() external { + function test_CalculatePixelWidth_Caption() external view { bool largeFont = false; assertEq(cpw("Progress", largeFont), small("Progress"), "pixel width"); assertEq(cpw("Status", largeFont), small("Status"), "pixel width"); @@ -33,7 +33,7 @@ contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(cpw("Duration", largeFont), small("Duration"), "pixel width"); } - function test_CalculatePixelWidth_Progress() external { + function test_CalculatePixelWidth_Progress() external view { bool largeFont = true; assertEq(cpw("0%", largeFont), large("0%"), "pixel width"); assertEq(cpw("0.01%", largeFont), large("0.01%"), "pixel width"); @@ -45,7 +45,7 @@ contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(cpw("100%", largeFont), large("100%"), "pixel width"); } - function test_CalculatePixelWidth_Status() external { + function test_CalculatePixelWidth_Status() external view { bool largeFont = true; assertEq(cpw("Depleted", largeFont), large("Depleted"), "pixel width"); assertEq(cpw("Canceled", largeFont), large("Canceled"), "pixel width"); @@ -54,7 +54,7 @@ contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(cpw("Pending", largeFont), large("Pending"), "pixel width"); } - function test_CalculatePixelWidth_Streamed() external { + function test_CalculatePixelWidth_Streamed() external view { bool largeFont = true; assertEq(cpw("< 1", largeFont), large("< 1"), "pixel width"); assertEq(cpw("≥ 42.73K", largeFont), large(" 42.73K") + CHAR_WIDTH_LARGE, "pixel width"); @@ -64,7 +64,7 @@ contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(cpw("≥ 999.99T", largeFont), large(" 999.99T") + CHAR_WIDTH_LARGE, "pixel width"); } - function test_CalculatePixelWidth_Duration() external { + function test_CalculatePixelWidth_Duration() external view { bool largeFont = true; assertEq(cpw("< 1 Day", largeFont), large("< 1 Day"), "pixel width"); assertEq(cpw("1 Day", largeFont), large("1 Day"), "pixel width"); diff --git a/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol b/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol index e30d6bdba..1345780df 100644 --- a/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol +++ b/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol @@ -4,21 +4,21 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract CalculateStreamedPercentage_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function test_CalculateStreamedPercentage_Zero() external { + function test_CalculateStreamedPercentage_Zero() external view { uint256 actualStreamedPercentage = nftDescriptorMock.calculateStreamedPercentage_({ streamedAmount: 0, depositedAmount: 1337e18 }); uint256 expectedStreamedPercentage = 0; assertEq(actualStreamedPercentage, expectedStreamedPercentage, "streamedPercentage"); } - function test_CalculateStreamedPercentage_Streaming() external { + function test_CalculateStreamedPercentage_Streaming() external view { uint256 actualStreamedPercentage = nftDescriptorMock.calculateStreamedPercentage_({ streamedAmount: 100e18, depositedAmount: 400e18 }); uint256 expectedStreamedPercentage = 2500; assertEq(actualStreamedPercentage, expectedStreamedPercentage, "streamedPercentage"); } - function test_CalculateStreamedPercentage_Settled() external { + function test_CalculateStreamedPercentage_Settled() external view { uint256 actualStreamedPercentage = nftDescriptorMock.calculateStreamedPercentage_({ streamedAmount: 1337e18, depositedAmount: 1337e18 }); uint256 expectedStreamedPercentage = 10_000; diff --git a/test/unit/concrete/nft-descriptor/generateAttributes.t.sol b/test/unit/concrete/nft-descriptor/generateAttributes.t.sol index c0b005706..1c5f9403d 100644 --- a/test/unit/concrete/nft-descriptor/generateAttributes.t.sol +++ b/test/unit/concrete/nft-descriptor/generateAttributes.t.sol @@ -5,14 +5,14 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract GenerateAttributes_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function test_GenerateAttributes_Empty() external { + function test_GenerateAttributes_Empty() external view { string memory actualAttributes = nftDescriptorMock.generateAttributes_("", "", ""); string memory expectedAttributes = '[{"trait_type":"Asset","value":""},{"trait_type":"Sender","value":""},{"trait_type":"Status","value":""}]'; assertEq(actualAttributes, expectedAttributes, "metadata attributes"); } - function test_GenerateAttributes() external { + function test_GenerateAttributes() external view { string memory actualAttributes = nftDescriptorMock.generateAttributes_("DAI", "0x50725493D337CdC4e381f658e10d29d128BD6927", "Streaming"); string memory expectedAttributes = diff --git a/test/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/unit/concrete/nft-descriptor/generateDescription.t.sol index 58664a40f..cb5f6ecbf 100644 --- a/test/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/test/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -10,7 +10,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T string internal constant INFO_TRANSFERABLE = unicode"⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient."; - function test_GenerateDescription_Empty() external { + function test_GenerateDescription_Empty() external view { string memory actualDescription = nftDescriptorMock.generateDescription_("", "", "", "", "", true); string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier V2 ", @@ -27,7 +27,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(actualDescription, expectedDescription, "metadata description"); } - function test_GenerateDescription_NonTransferable() external { + function test_GenerateDescription_NonTransferable() external view { string memory actualDescription = nftDescriptorMock.generateDescription_( "Lockup Linear", dai.symbol(), @@ -58,7 +58,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(actualDescription, expectedDescription, "metadata description"); } - function test_GenerateDescription() external { + function test_GenerateDescription() external view { string memory actualDescription = nftDescriptorMock.generateDescription_( "Lockup Linear", dai.symbol(), diff --git a/test/unit/concrete/nft-descriptor/generateName.t.sol b/test/unit/concrete/nft-descriptor/generateName.t.sol index 13c6631d4..b65208ac8 100644 --- a/test/unit/concrete/nft-descriptor/generateName.t.sol +++ b/test/unit/concrete/nft-descriptor/generateName.t.sol @@ -16,13 +16,13 @@ contract GenerateName_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { return string.concat("Sablier V2 Lockup Linear #", streamId); } - function test_GenerateName_Empty() external { + function test_GenerateName_Empty() external view { assertEq(gn("", ""), "Sablier V2 #", "metadata name"); assertEq(gn("A", ""), "Sablier V2 A #", "metadata name"); assertEq(gn("", "1"), "Sablier V2 #1", "metadata name"); } - function test_GenerateName() external { + function test_GenerateName() external view { assertEq(gn("Lockup Dynamic", "1"), dyn("1"), "metadata name"); assertEq(gn("Lockup Dynamic", "42"), dyn("42"), "metadata name"); assertEq(gn("Lockup Dynamic", "1337"), dyn("1337"), "metadata name"); diff --git a/test/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/unit/concrete/nft-descriptor/generateSVG.t.sol index 750124ed0..8322a26ed 100644 --- a/test/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -11,7 +11,7 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { /// @dev If you need to update the hard-coded token URI: /// 1. Use "vm.writeFile" to log the strings to a file. /// 2. Remember to escape 'Courier New' with \'Courier New\'. - function test_GenerateSVG_Pending() external { + function test_GenerateSVG_Pending() external view { string memory actualSVG = nftDescriptorMock.generateSVG_( NFTSVG.SVGParams({ accentColor: "hsl(155,18%,30%)", @@ -31,7 +31,7 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { assertEq(actualSVG, expectedSVG, "SVG mismatch"); } - function test_GenerateSVG_Streaming() external { + function test_GenerateSVG_Streaming() external view { string memory actualSVG = nftDescriptorMock.generateSVG_( NFTSVG.SVGParams({ accentColor: "hsl(114,3%,53%)", @@ -51,7 +51,7 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { assertEq(actualSVG, expectedSVG, "SVG mismatch"); } - function test_GenerateSVG_Depleted() external { + function test_GenerateSVG_Depleted() external view { string memory actualSVG = nftDescriptorMock.generateSVG_( NFTSVG.SVGParams({ accentColor: "hsl(123,25%,44%)", diff --git a/test/unit/concrete/nft-descriptor/hourglass.t.sol b/test/unit/concrete/nft-descriptor/hourglass.t.sol index ff331479c..9841de5a4 100644 --- a/test/unit/concrete/nft-descriptor/hourglass.t.sol +++ b/test/unit/concrete/nft-descriptor/hourglass.t.sol @@ -10,31 +10,31 @@ import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract Hourglass_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { using LibString for string; - function test_Hourglass_Pending() external { + function test_Hourglass_Pending() external view { string memory hourglass = nftDescriptorMock.hourglass_("pending"); uint256 index = hourglass.indexOf(SVGElements.HOURGLASS_UPPER_BULB); assertNotEq(index, LibString.NOT_FOUND, "hourglass upper bulb should be present"); } - function test_Hourglass_Streaming() external { + function test_Hourglass_Streaming() external view { string memory hourglass = nftDescriptorMock.hourglass_("Streaming"); uint256 index = hourglass.indexOf(SVGElements.HOURGLASS_UPPER_BULB); assertNotEq(index, LibString.NOT_FOUND, "hourglass upper bulb should be present"); } - function test_Hourglass_Settled() external { + function test_Hourglass_Settled() external view { string memory hourglass = nftDescriptorMock.hourglass_("Settled"); uint256 index = hourglass.indexOf(SVGElements.HOURGLASS_UPPER_BULB); assertEq(index, LibString.NOT_FOUND, "hourglass upper bulb should NOT be present"); } - function test_Hourglass_Canceled() external { + function test_Hourglass_Canceled() external view { string memory hourglass = nftDescriptorMock.hourglass_("Canceled"); uint256 index = hourglass.indexOf(SVGElements.HOURGLASS_UPPER_BULB); assertNotEq(index, LibString.NOT_FOUND, "hourglass upper bulb should be present"); } - function test_Hourglass_Depleted() external { + function test_Hourglass_Depleted() external view { string memory hourglass = nftDescriptorMock.hourglass_("Depleted"); uint256 index = hourglass.indexOf(SVGElements.HOURGLASS_UPPER_BULB); assertEq(index, LibString.NOT_FOUND, "hourglass upper bulb should NOT be present"); diff --git a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol b/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol index 09c396f11..109d87399 100644 --- a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol @@ -6,7 +6,7 @@ import { SVGElements } from "src/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract StringifyCardType_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function test_StringifyCardType() external { + function test_StringifyCardType() external view { assertEq(nftDescriptorMock.stringifyCardType_(SVGElements.CardType.PROGRESS), "Progress"); assertEq(nftDescriptorMock.stringifyCardType_(SVGElements.CardType.STATUS), "Status"); assertEq(nftDescriptorMock.stringifyCardType_(SVGElements.CardType.AMOUNT), "Amount"); diff --git a/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol b/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol index 4936545a0..4e5862a32 100644 --- a/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol @@ -8,17 +8,17 @@ contract StringifyFractionalAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Conc return nftDescriptorMock.stringifyFractionalAmount_(amount); } - function test_FractionalAmount_Zero() external { + function test_FractionalAmount_Zero() external view { assertEq(sfa(0), "", "fractional part mismatch"); } - function test_FractionalAmount_LeadingZero() external { + function test_FractionalAmount_LeadingZero() external view { assertEq(sfa(1), ".01", "fractional part mismatch"); assertEq(sfa(5), ".05", "fractional part mismatch"); assertEq(sfa(9), ".09", "fractional part mismatch"); } - function test_FractionalAmount_NoLeadingZero() external { + function test_FractionalAmount_NoLeadingZero() external view { assertEq(sfa(10), ".10", "fractional part mismatch"); assertEq(sfa(12), ".12", "fractional part mismatch"); assertEq(sfa(33), ".33", "fractional part mismatch"); diff --git a/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol b/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol index 15a676db1..d0d72913d 100644 --- a/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol @@ -8,7 +8,7 @@ contract StringifyPercentage_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T return nftDescriptorMock.stringifyPercentage_(percentage); } - function test_StringifyPercentage_NoFractionalPart() external { + function test_StringifyPercentage_NoFractionalPart() external view { assertEq(sp(0), "0%", "percentage mismatch"); assertEq(sp(100), "1%", "percentage mismatch"); assertEq(sp(300), "3%", "percentage mismatch"); @@ -17,7 +17,7 @@ contract StringifyPercentage_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T assertEq(sp(10_000), "100%", "percentage mismatch"); } - function test_StringifyPercentage_FractionalPart() external { + function test_StringifyPercentage_FractionalPart() external view { assertEq(sp(1), "0.01%", "percentage mismatch"); assertEq(sp(42), "0.42%", "percentage mismatch"); assertEq(sp(314), "3.14%", "percentage mismatch"); diff --git a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol b/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol index 62dbe04f9..a18b115f7 100644 --- a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol +++ b/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol @@ -6,7 +6,7 @@ import { Lockup } from "src/types/DataTypes.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract StringifyStatus_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function test_StringifyStatus() external { + function test_StringifyStatus() external view { assertEq(nftDescriptorMock.stringifyStatus_(Lockup.Status.DEPLETED), "Depleted", "depleted status mismatch"); assertEq(nftDescriptorMock.stringifyStatus_(Lockup.Status.CANCELED), "Canceled", "canceled status mismatch"); assertEq(nftDescriptorMock.stringifyStatus_(Lockup.Status.STREAMING), "Streaming", "streaming status mismatch"); diff --git a/test/unit/fuzz/transferAdmin.t.sol b/test/unit/fuzz/transferAdmin.t.sol index 9b44c3be2..dd4412cbc 100644 --- a/test/unit/fuzz/transferAdmin.t.sol +++ b/test/unit/fuzz/transferAdmin.t.sol @@ -8,10 +8,10 @@ import { Adminable_Unit_Shared_Test } from "../shared/Adminable.t.sol"; contract TransferAdmin_Unit_Fuzz_Test is Adminable_Unit_Shared_Test { function testFuzz_RevertWhen_CallerNotAdmin(address eve) external { vm.assume(eve != address(0) && eve != users.admin); - assumeNoPrecompiles(eve); + assumeNotPrecompile(eve); // Make Eve the caller in this test. - changePrank(eve); + resetPrank(eve); // Run the test. vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, eve)); diff --git a/test/unit/shared/Adminable.t.sol b/test/unit/shared/Adminable.t.sol index 4136fe729..9a0ffe2b8 100644 --- a/test/unit/shared/Adminable.t.sol +++ b/test/unit/shared/Adminable.t.sol @@ -10,7 +10,7 @@ abstract contract Adminable_Unit_Shared_Test is Base_Test { function setUp() public virtual override { Base_Test.setUp(); deployConditionally(); - changePrank({ msgSender: users.admin }); + resetPrank({ msgSender: users.admin }); } /// @dev Conditionally deploys {AdminableMock} normally or from a source precompiled with `--via-ir`. diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 74cf9d617..2dea51dab 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -3,22 +3,21 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; -import { PRBTest } from "@prb/test/src/PRBTest.sol"; import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; -abstract contract Assertions is PRBTest, PRBMathAssertions { +abstract contract Assertions is PRBMathAssertions { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ - event LogNamedArray(string key, LockupDynamic.Segment[] segments); + event log_named_array(string key, LockupDynamic.Segment[] segments); - event LogNamedArray(string key, LockupTranched.Tranche[] tranches); + event log_named_array(string key, LockupTranched.Tranche[] tranches); - event LogNamedUint128(string key, uint128 value); + event log_named_uint128(string key, uint128 value); - event LogNamedUint40(string key, uint40 value); + event log_named_uint40(string key, uint40 value); /*////////////////////////////////////////////////////////////////////////// ASSERTIONS @@ -32,12 +31,12 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { } /// @dev Compares two {IERC20} values. - function assertEq(IERC20 a, IERC20 b) internal { + function assertEq(IERC20 a, IERC20 b) internal pure { assertEq(address(a), address(b)); } /// @dev Compares two {IERC20} values. - function assertEq(IERC20 a, IERC20 b, string memory err) internal { + function assertEq(IERC20 a, IERC20 b, string memory err) internal pure { assertEq(address(a), address(b), err); } @@ -109,9 +108,9 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two {LockupDynamic.Segment[]} arrays. function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit Log("Error: a == b not satisfied [LockupDynamic.Segment[]]"); - emit LogNamedArray(" Left", a); - emit LogNamedArray(" Right", b); + emit log("Error: a == b not satisfied [LockupDynamic.Segment[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); fail(); } } @@ -119,7 +118,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two `LockupDynamic.Segment[]` arrays. function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b, string memory err) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit LogNamedString("Error", err); + emit log_named_string("Error", err); assertEq(a, b); } } @@ -127,9 +126,9 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two {LockupTranched.Tranche[]} arrays. function assertEq(LockupTranched.Tranche[] memory a, LockupTranched.Tranche[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit Log("Error: a == b not satisfied [LockupTranched.Tranche[]]"); - emit LogNamedArray(" Left", a); - emit LogNamedArray(" Right", b); + emit log("Error: a == b not satisfied [LockupTranched.Tranche[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); fail(); } } @@ -143,27 +142,27 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit LogNamedString("Error", err); + emit log_named_string("Error", err); assertEq(a, b); } } /// @dev Compares two {Lockup.Status} enum values. - function assertEq(Lockup.Status a, Lockup.Status b) internal { + function assertEq(Lockup.Status a, Lockup.Status b) internal pure { assertEq(uint256(a), uint256(b), "status"); } /// @dev Compares two {Lockup.Status} enum values. - function assertEq(Lockup.Status a, Lockup.Status b, string memory err) internal { + function assertEq(Lockup.Status a, Lockup.Status b, string memory err) internal pure { assertEq(uint256(a), uint256(b), err); } /// @dev Compares two `uint128` numbers. function assertEqUint128(uint128 a, uint128 b) internal { if (a != b) { - emit Log("Error: a == b not satisfied [uint128]"); - emit LogNamedUint128(" Left", a); - emit LogNamedUint128(" Right", b); + emit log("Error: a == b not satisfied [uint128]"); + emit log_named_uint128(" Left", a); + emit log_named_uint128(" Right", b); fail(); } } @@ -171,7 +170,7 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two `uint128` numbers. function assertEqUint128(uint128 a, uint128 b, string memory err) internal { if (a != b) { - emit LogNamedString("Error", err); + emit log_named_string("Error", err); assertEqUint128(a, b); } } @@ -179,9 +178,9 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two `uint40` numbers. function assertEqUint40(uint40 a, uint40 b) internal { if (a != b) { - emit Log("Error: a == b not satisfied [uint40]"); - emit LogNamedUint40(" Left", a); - emit LogNamedUint40(" Right", b); + emit log("Error: a == b not satisfied [uint40]"); + emit log_named_uint40(" Left", a); + emit log_named_uint40(" Right", b); fail(); } } @@ -189,18 +188,18 @@ abstract contract Assertions is PRBTest, PRBMathAssertions { /// @dev Compares two `uint40` numbers. function assertEqUint40(uint40 a, uint40 b, string memory err) internal { if (a != b) { - emit LogNamedString("Error", err); + emit log_named_string("Error", err); assertEqUint40(a, b); } } /// @dev Compares two {Lockup.Status} enum values. - function assertNotEq(Lockup.Status a, Lockup.Status b) internal { + function assertNotEq(Lockup.Status a, Lockup.Status b) internal pure { assertNotEq(uint256(a), uint256(b), "status"); } /// @dev Compares two {Lockup.Status} enum values. - function assertNotEq(Lockup.Status a, Lockup.Status b, string memory err) internal { + function assertNotEq(Lockup.Status a, Lockup.Status b, string memory err) internal pure { assertNotEq(uint256(a), uint256(b), err); } } diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index 828e1ff88..d5b9bfda4 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -2,11 +2,11 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { PRBTest } from "@prb/test/src/PRBTest.sol"; +import { StdAssertions } from "forge-std/src/StdAssertions.sol"; import { BaseScript } from "script/Base.s.sol"; -contract BaseScript_Test is PRBTest { +contract BaseScript_Test is StdAssertions { using Strings for uint256; BaseScript internal baseScript; diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index a7c8564f4..e9d11f6eb 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -4,9 +4,10 @@ pragma solidity >=0.8.22; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; abstract contract Constants { - uint40 internal constant MAY_1_2023 = 1_682_899_200; UD60x18 internal constant MAX_BROKER_FEE = UD60x18.wrap(0.1e18); // 10% - uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 uint128 internal constant MAX_UINT128 = type(uint128).max; + uint256 internal constant MAX_UINT256 = type(uint256).max; uint40 internal constant MAX_UINT40 = type(uint40).max; + uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 + uint40 internal constant MAY_1_2024 = 1_714_518_000; } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index e755694e2..8a22b5ec7 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -42,7 +42,7 @@ contract Defaults is Constants { //////////////////////////////////////////////////////////////////////////*/ constructor() { - START_TIME = uint40(MAY_1_2023) + 2 days; + START_TIME = uint40(MAY_1_2024) + 2 days; CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_COUNT); diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index f9a0073ad..d38753d7c 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -13,7 +13,6 @@ import { Base_Test } from "../Base.t.sol"; contract Precompiles_Test is Base_Test { using LibString for address; - using LibString for string; Precompiles internal precompiles = new Precompiles(); @@ -100,9 +99,10 @@ contract Precompiles_Test is Base_Test { returns (bytes memory) { return vm.parseBytes( - vm.toString(bytecode).replace({ - search: expectedAddress.toHexStringNoPrefix(), - replacement: actualAddress.toHexStringNoPrefix() + vm.replace({ + input: vm.toString(bytecode), + from: expectedAddress.toHexStringNoPrefix(), + to: actualAddress.toHexStringNoPrefix() }) ); } diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 736988ece..0a1b1b644 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -3,19 +3,11 @@ pragma solidity >=0.8.22; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol"; - -import { Vm } from "@prb/test/src/PRBTest.sol"; -import { StdUtils } from "forge-std/src/StdUtils.sol"; +import { CommonBase } from "forge-std/src/Base.sol"; import { LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; -abstract contract Utils is StdUtils, PRBMathUtils { - /// @dev The virtual address of the Foundry VM. - address private constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - - /// @dev An instance of the Foundry VM, which contains cheatcodes for testing. - Vm private constant vm = Vm(VM_ADDRESS); - +abstract contract Utils is CommonBase, PRBMathUtils { /// @dev Bounds a `uint128` number. function boundUint128(uint128 x, uint128 min, uint128 max) internal pure returns (uint128) { return uint128(_bound(uint256(x), uint256(min), uint256(max))); @@ -76,8 +68,14 @@ abstract contract Utils is StdUtils, PRBMathUtils { } /// @dev Checks if the Foundry profile is "test-optimized". - function isTestOptimizedProfile() internal returns (bool) { + function isTestOptimizedProfile() internal view returns (bool) { string memory profile = vm.envOr({ name: "FOUNDRY_PROFILE", defaultValue: string("default") }); return Strings.equal(profile, "test-optimized"); } + + /// @dev Stops the active prank and sets a new one. + function resetPrank(address msgSender) internal { + vm.stopPrank(); + vm.startPrank(msgSender); + } } From 15b1a2a32fbf74ca5f4265408b000916fe1e10a4 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 2 Apr 2024 16:54:42 +0100 Subject: [PATCH 078/132] Reorder conditions for if-else in LD to increase branch coverage (#874) * refactor: reorder conditions for if-else in LD calculate streamed amount test: increase branch coverage for SablierV2LockupDynamic.sol * doc: helper comments --- precompiles/Precompiles.sol | 2 +- src/SablierV2LockupDynamic.sol | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 305f44aa7..3acf8d3fb 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -25,7 +25,7 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f1962005a3b3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156399081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab82614242565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614242565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614242565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614680565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614197565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d8588614680565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614212565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a614242565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be9161426a565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b87825285522001541694613151818988614680565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e61343783614197565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b9161426a565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c88614680565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a890614356565b90565b6137a890614285565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b036040840151166020610100850151015190614536565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b03835116903090339061460f565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b03610100860151511690339061460f565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b5151169061426a565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b8060005260096020526141b06002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146141e357506001600160801b039150602001511690565b5460f81c6141f557506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b3d1561423d573d90614223826129b2565b916142316040519384612990565b82523d6000602084013e565b606090565b6137a89061424f81614197565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff6142ba600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146da565b91808252600a602052604082208054156143425790829167ffffffffffffffff93526143146020832054828452600960205261430f6001600160801b03968760026040882001541696879360801c16906147ca565b614838565b92831361432a57505061432690614922565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161437c83612973565b80549661012061440260026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a602052614419858520612df7565b9184968087614427866139f8565b5101511692828288955b16106145005750916144b561430f928488816144ba98976001600160801b039e8f61445c898c613a05565b5151169d8e9a67ffffffffffffffff60206144778c84613a05565b510151169984836144888385613a05565b51015116965080156144f4576144a49293506000190190613a05565b5101511680925b03169203166146da565b6147ca565b9283136144d35750506144cd8391614922565b16011690565b5160200151929392831692841683101591506144ef9050575090565b905090565b505050511680926144ab565b8093986001600160801b0390816145178c89613a05565b51511601169801928282808a61452d888a613a05565b51015116614431565b9190916040519061454682612943565b600091828152826020820152936001600160801b03928383169182156145f05767016345785d8a00008082116145b957506145828591846154ea565b16602087019281845211156145a5575090826145a092511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061460482612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761467e9260405261495e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261467e916146d5606483612990565b61495e565b600160ff1b8082149081156147c0575b5061479657600081121561478d57614713816000035b60008412156147865783600003906149fa565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474f57600019911813156147495790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fa565b61471381614700565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146ea565b806147e557506147e057670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483257508061480a575050670de0b6b3a764000090565b670de0b6b3a7640000811461482e576148299061430f6137a893614af4565b614c36565b5090565b91505090565b600160ff1b808214908115614918575b506148ee5760008112156148e557614871816000035b60008412156148de5783600003906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a757600019911813156147495790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154ea565b6148718161485e565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614848565b6000811261492d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614989600080836020829551910182875af1614982614212565b9084615599565b9081519182151592836149d2575b5050506149a15750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614997565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab65782851015614a7a57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac4570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac4576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0557670de0b6b3a764000092838112614be257506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd657506706f05b59d3b20000905b848213614baa5750505050500290565b808391020590671bc16d674ec80000821215614bc9575b831d90614b9a565b8091950194831d90614bc1565b93505093925050020290565b6000199392508015614ac4576ec097ce7bc90715b34b9f10000000000591614b15565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c655768033dd1780914b9711419811261384a57614c5c90600003614c36565b6137a890614ada565b680a688906bd8affffff81136154b957670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539c575b66ff0000000000008316615294575b65ff00000000008316615194575b64ff00000000831661509c575b63ff0000008316614fac575b62ff00008316614ec4575b61ff008316614de4575b60ff8316614d0d575b02911c60bf031c90565b60808316614dd2575b838316614dc0575b60208316614dae575b60108316614d9c575b60088316614d8a575b60048316614d78575b60028316614d66575b6001831615614d03576801000000000000000102831c614d03565b6801000000000000000102831c614d4b565b6801000000000000000302831c614d42565b6801000000000000000602831c614d39565b6801000000000000000b02831c614d30565b6801000000000000001602831c614d27565b6801000000000000002c02831c614d1e565b6801000000000000005902831c614d16565b6180008316614eb2575b6140008316614ea0575b6120008316614e8e575b6110008316614e7c575b6108008316614e6a575b6104008316614e58575b6102008316614e46575b610100831615614cfa57680100000000000000b102831c614cfa565b6801000000000000016302831c614e2a565b680100000000000002c602831c614e20565b6801000000000000058c02831c614e16565b68010000000000000b1702831c614e0c565b6801000000000000162e02831c614e02565b68010000000000002c5d02831c614df8565b680100000000000058b902831c614dee565b628000008316614f9a575b624000008316614f88575b622000008316614f76575b621000008316614f64575b620800008316614f52575b620400008316614f40575b620200008316614f2e575b62010000831615614cf0576801000000000000b17202831c614cf0565b680100000000000162e402831c614f11565b6801000000000002c5c802831c614f06565b68010000000000058b9102831c614efb565b680100000000000b172102831c614ef0565b68010000000000162e4302831c614ee5565b680100000000002c5c8602831c614eda565b6801000000000058b90c02831c614ecf565b6380000000831661508a575b63400000008316615078575b63200000008316615066575b63100000008316615054575b63080000008316615042575b63040000008316615030575b6302000000831661501e575b6301000000831615614ce55768010000000000b1721802831c614ce5565b6801000000000162e43002831c615000565b68010000000002c5c86002831c614ff4565b680100000000058b90c002831c614fe8565b6801000000000b17217f02831c614fdc565b680100000000162e42ff02831c614fd0565b6801000000002c5c85fe02831c614fc4565b68010000000058b90bfc02831c614fb8565b6480000000008316615182575b6440000000008316615170575b642000000000831661515e575b641000000000831661514c575b640800000000831661513a575b6404000000008316615128575b6402000000008316615116575b640100000000831615614cd957680100000000b17217f802831c614cd9565b68010000000162e42ff102831c6150f7565b680100000002c5c85fe302831c6150ea565b6801000000058b90bfce02831c6150dd565b68010000000b17217fbb02831c6150d0565b6801000000162e42fff002831c6150c3565b68010000002c5c8601cc02831c6150b6565b680100000058b90c0b4902831c6150a9565b658000000000008316615282575b654000000000008316615270575b65200000000000831661525e575b65100000000000831661524c575b65080000000000831661523a575b650400000000008316615228575b650200000000008316615216575b65010000000000831615614ccc576801000000b17218355102831c614ccc565b680100000162e430e5a202831c6151f6565b6801000002c5c863b73f02831c6151e8565b68010000058b90cf1e6e02831c6151da565b680100000b1721bcfc9a02831c6151cc565b68010000162e43f4f83102831c6151be565b680100002c5c89d5ec6d02831c6151b0565b6801000058b91b5bc9ae02831c6151a2565b6680000000000000831661538a575b66400000000000008316615378575b66200000000000008316615366575b66100000000000008316615354575b66080000000000008316615342575b66040000000000008316615330575b6602000000000000831661531e575b6601000000000000831615614cbe5768010000b17255775c0402831c614cbe565b6801000162e525ee054702831c6152fd565b68010002c5cc37da949202831c6152ee565b680100058ba01fb9f96d02831c6152df565b6801000b175effdc76ba02831c6152d0565b680100162f3904051fa102831c6152c1565b6801002c605e2e8cec5002831c6152b2565b68010058c86da1c09ea202831c6152a3565b678000000000000000831661549a575b6740000000000000008316615488575b6720000000000000008316615476575b6710000000000000008316615464575b6708000000000000008316615452575b6704000000000000008316615440575b670200000000000000831661542e575b670100000000000000831615614caf57680100b1afa5abcbed6102831c614caf565b68010163da9fb33356d802831c61540c565b680102c9a3e778060ee702831c6153fc565b6801059b0d31585743ae02831c6153ec565b68010b5586cf9890f62a02831c6153dc565b6801172b83c7d517adce02831c6153cc565b6801306fe0a31b7152df02831c6153bc565b5077b504f333f9de6484800000000000000000000000000000006153ac565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558857670de0b6b3a7640000908183101561555157947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d857508051156155ae57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615623575b6155e9575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e156fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962005a3a3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556156389081620004028239608051816139a6015260a051818181610c9f0152613a6d0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126dc57508063027b6744146126b957806306fdde03146125f3578063081812fc146125d5578063095ea7b3146124d45780631400ecec1461242f5780631c1cdd4c146123c95780631e99d569146123ab57806323b872dd1461239457806331df3d481461228857806340e58ee514611f8e578063425d30dd14611f3a57806342842e0e14611f0057806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612809565b6044356001600160801b038116810361029d5761029b9161029361399c565b6004356133a6565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612809565b6103ab82614242565b91612ffb565b3461029d57604036600319011261029d576103ca6127f3565b6103d2612809565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614242565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d81612943565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161056083612943565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b282613735565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ce565b0390f35b9091503d806000833e6106368183612990565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129b2565b926106796040519485612990565b81845284828401011161029d57610695918480850191016127ab565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612809565b6106cc61399c565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614242565b6001600160801b0381166107a5575b508181161561078d578361073591613857565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ffb565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127f3565b6108e9612809565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129b2565b926109246040519485612990565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612df7565b604051918291602083526020830190612899565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d0565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127f3565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612990565b61061f6040519282849384528301906127ce565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d0565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612da4565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612973565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dc3565b610120820152610efc6004356137d0565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff6040830151166060830151151591610100840151151560c0850151151560e086015115159060043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612df7565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612899565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612868565b9061116061399c565b6000915b80831061116d57005b611178838284612d49565b359261118261399c565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b156114385761121085613758565b91856000528089526112286002604060002001612dc3565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a06565b9601511690612a06565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a61467f565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295f565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399c565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d0565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295f565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127f3565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127f3565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba600435613735565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399c565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c7a565b9182519161194f83612c62565b9261195d6040519485612990565b808452601f1961196c82612c62565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139f8565b515116828a6119a7846139f8565b51015116858060406119b8866139f8565b5101511689011690604051926119cd84612927565b83528b83015260408201526119e1886139f8565b526119eb876139f8565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d83565b92611a1960248301612d83565b92611a2660448401612d6f565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d97565b9481611a6660a48c01612d97565b976040519d8e61290a565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d1a565b610100820152613a19565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a05565b5151169a613a05565b5101511694600019890190613a05565b51015116816040611afe888c613a05565b5101511601169160405193611b1285612927565b84528301526040820152611b26828c613a05565b52611b31818b613a05565b500188906119f3565b611b42612da4565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612868565b9160243590811161029d57611b9b903690600401612868565b9091611ba561399c565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d49565b35611bd5838987612d49565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d49565b612d6f565b91611c0961399c565b6133a6565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614197565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d0565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399c565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecf57611d838261412e565b156116675781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c16159081611ec5575b5080611ebd575b611ea5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e6a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e5257005b60249060405190637e27328960e01b82526004820152fd5b611e8b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611e02565b60248360405190630da9b01360e01b82526004820152fd5b506000611dc2565b9050151584611dbb565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0e36612833565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e87565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fac61399c565b8160005260099081815260ff60016040600020015460a81c16156122715782600052818152604060002060ff600182015460a01c166000146120005760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612259576120288360005260096020526001600160a01b0360406000205416331490565b1561223a5761203683613758565b928060005282825261204e6002604060002001612dc3565b916001600160801b0394858451168682161015612222578260005284825260ff60406000205460f01c161561220a57816120df82888796956120d57ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a06565b9701511690612a06565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121f0575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121798d858861467f565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121ab57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e757005b61029b9061295f565b60018101600160a01b60ff60a01b19825416179055612126565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122c361399c565b604051916122d08361290a565b6122dc8260040161281f565b83526122ea6024830161281f565b60208401526122fb604483016129ce565b604084015260648201356001600160a01b038116810361029d576060840152612326608483016128fd565b608084015261233760a483016128fd565b60a084015261234860c48301612c50565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123846020953690602460048201359101612c7a565b60e0840152610104369101612d1a565b3461029d5761029b6123a536612833565b91612a1f565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757612403906137d0565b6005811015610a4f578060209115908115612424575b506040519015158152f35b600191501482612419565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124c2575b612499575b50506001600160801b0360405191168152f35b6124bb92506001600160801b0360026124b59201541691613758565b90612a06565b8280612486565b5060ff600182015460a01c1615612481565b3461029d57604036600319011261029d576124ed6127f3565b6024356124f981613735565b331515806125c2575b80612594575b6125645781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612508565b50336001600160a01b0382161415612502565b3461029d57602036600319011261029d5760206118ba6004356129e2565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126af575b6020948585108414610c67578587948686529182600014610c475750506001146126525750610bd692500383612990565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612697575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612680565b92607f1692612621565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612781575b8115612757575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612750565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612749565b60005b8381106127be5750506000910152565b81810151838201526020016127ae565b906020916127e7815180928185528580860191016127ab565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b9575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128ab565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129eb81613735565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d57600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081612c46575b5080612c3e575b612c27578685526003815282848620541694873315159384612b77575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b3f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612b115750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b6082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612aad565b91929380915090612be6575b15612b915790878392612a84565b848887612bae576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612c0b575b80612b835750878252600583523384868420541614612b83565b5085825260068352848220338352835260ff8583205416612bf1565b602487855190630da9b01360e01b82526004820152fd5b506001612a67565b9050151538612a60565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c8682612c62565b604094612c966040519283612990565b8195848352602080930191606080960285019481861161029d57925b858410612cc25750505050505050565b868483031261029d57825190612cd782612927565b612ce0856129ce565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d0b868801612c50565b86820152815201930192612cb2565b919082604091031261029d57604051612d3281612943565b6020808294612d408161281f565b84520135910152565b9190811015612d595760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612db182612927565b60006040838281528260208201520152565b90604051612dd081612927565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612e0381612c62565b92604093612e146040519182612990565b82815280946020809201926000526020600020906000935b858510612e3b57505050505050565b60018481928451612e4b81612927565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e2c565b9190612e94828285612a1f565b803b612ea1575b50505050565b612efd6001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ce565b03906020816000938185885af190829082612f93575b5050612f4a5782612f22614212565b8051919082612f435760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f7b575038808080612e9b565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612ff3575b81612fb060209383612990565b81010312612fef5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fec5750903880612f13565b80fd5b5080fd5b3d9150612fa3565b9291909261300761399c565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133905784885281865260ff6001858a20015460a01c16613379576001600160a01b0391828216928315613369576001600160801b039384861691821561335257888c5260038a5280888d205416938483141580613342575b61331f5761308d8a614242565b87811685116132ee57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130be9161426a565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130f390612dc3565b90808683015116918184818351169201511661310e91612a06565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132c1575b8782528552200154169461315181898861467f565b8a51908152a480331415806132b7575b613252575b823314159081613247575b8161323c575b506131ab575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613238578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613229575b85948161317d565b6132329061295f565b38613221565b8780fd5b905082141538613177565b833b15159150613171565b803b156132b3578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af16132a4575b50613166565b6132ad9061295f565b3861329e565b8880fd5b50803b1515613161565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b19815416905561313c565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061334c8a61412e565b15613080565b60248989519063d2aabcd960e01b82526004820152fd5b6004865163630d074f60e11b8152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613390578785815281875260ff6001868320015460a01c1661371e576001600160a01b039081851692831561370e576001600160801b03938486169182156136f75789845260038b528489852054169485831415806136e7575b6136c45761344b8b838e61343783614197565b9289525260028c8820015460801c90612a06565b87811685116136935750908b8b928387528282528b808820998b838c54169b6002015460801c9061347b9161426a565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134b090612dc3565b818086830151169381835116920151166134c991612a06565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613665575b848852825260018c88200154169461350d818c8861467f565b8b51908152a4813314158061365b575b6135f5575b508133141590816135ea575b816135df575b50613567575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135db578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c3575b808061317d565b6135cd869161295f565b6135d757846135bc565b8480fd5b8280fd5b905081141538613534565b823b1515915061352e565b813b15612fec578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613647575b50613522565b61365391929a5061295f565b973880613641565b50813b151561351d565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f4565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f18b61412e565b15613424565b60248a8a519063d2aabcd960e01b82526004820152fd5b6004875163630d074f60e11b8152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e52575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137c65760c81c1611156137b45750600a6020526001604060002054116000146137ab576137a890614356565b90565b6137a890614285565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137f7575050600490565b805460f81c613850575460a01c64ffffffffff16421061384a5761381a81613758565b9060005260096020526001600160801b03806002604060002001541691161060001461384557600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c16159081613992575b5080613987575b613970579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613938575b169283613922575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138fe565b61395986600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138f6565b602486885190630da9b01360e01b82526004820152fd5b508181161515613895565b905015153861388e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139ce57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d595760200190565b8051821015612d595760209160051b010190565b90613a3b6001600160801b036040840151166020610100850151015190614535565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141045780156140da57815180156140b0577f0000000000000000000000000000000000000000000000000000000000000000811161407f575064ffffffffff6040613aa4846139f8565b510151168110156140285750600090819082815184905b808210613f97575050505064ffffffffff421664ffffffffff8216811015613f575750506001600160801b0316808203613f20575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c578951996000198b0190613a05565b51015160c81b169560f01b16911617171717845560005b818110613e4e575050600185016007556001600160a01b03602083015116801561078d57613ca4866001600160a01b0392613857565b16613e1d57613ccf6001600160a01b036060840151166001600160801b03835116903090339061460e565b6001600160801b0360208201511680613ded575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de2613dc360808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6c8c612943565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612899565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e17906001600160a01b036060850151166001600160a01b03610100860151511690339061460e565b38613ce3565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6b8160e0870151613a05565b518254680100000000000000008110156110eb5760018101808555811015612d5957600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c6e565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbb906001600160801b03613fb28588613a05565b5151169061426a565b9364ffffffffff806040613fcf8685613a05565b51015116941680851115613feb57506001849301909291613abb565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040614039846139f8565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614173575b5050821561416157505090565b90915061416e33926129e2565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614154565b8060005260096020526141b06002604060002001612dc3565b816000526009602052604060002060ff600182015460a01c166000146141e357506001600160801b039150602001511690565b5460f81c6141f557506137a890613758565b6137a891506001600160801b036040818351169201511690612a06565b3d1561423d573d90614223826129b2565b916142316040519384612990565b82523d6000602084013e565b606090565b6137a89061424f81614197565b90600052600960205260026040600020015460801c90612a06565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff6142ba600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146d9565b91808252600a602052604082208054156143425790829167ffffffffffffffff93526143146020832054828452600960205261430f6001600160801b03968760026040882001541696879360801c16906147c9565b614837565b92831361432a57505061432690614921565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161437c83612973565b80549661012061440260026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dc3565b94019384528452600a602052614419858520612df7565b9184968087614427866139f8565b5101511692828288955b16106144ff5750916144a561430f928488816144aa98976001600160801b039e8f61445c898c613a05565b5151169d8e9a67ffffffffffffffff60206144778c84613a05565b510151169984836144888385613a05565b510151169650806144e457505050511680925b03169203166146d9565b6147c9565b9283136144c35750506144bd8391614921565b16011690565b5160200151929392831692841683101591506144df9050575090565b905090565b6144f49293506000190190613a05565b51015116809261449b565b8093986001600160801b0390816145168c89613a05565b51511601169801928282808a61452c888a613a05565b51015116614431565b9190916040519061454582612943565b600091828152826020820152936001600160801b03928383169182156145ef5767016345785d8a00008082116145b857506145818591846154e9565b16602087019281845211156145a45750908261459f92511690612a06565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061460382612943565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761467d9260405261495d565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261467d916146d4606483612990565b61495d565b600160ff1b8082149081156147bf575b5061479557600081121561478c57614712816000035b60008412156147855783600003906149f9565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161474e57600019911813156147485790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149f9565b614712816146ff565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146e9565b806147e457506147df57670de0b6b3a764000090565b600090565b90670de0b6b3a7640000808314614831575080614809575050670de0b6b3a764000090565b670de0b6b3a7640000811461482d576148289061430f6137a893614af3565b614c35565b5090565b91505090565b600160ff1b808214908115614917575b506148ed5760008112156148e457614870816000035b60008412156148dd5783600003906154e9565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a657600019911813156147485790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154e9565b6148708161485d565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614847565b6000811261492c5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614988600080836020829551910182875af1614981614212565b9084615598565b9081519182151592836149d1575b5050506149a05750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fef576020015190811591821503612fec5750388080614996565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab55782851015614a7957908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac3570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac3576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0457670de0b6b3a764000092838112614be157506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd557506706f05b59d3b20000905b848213614ba95750505050500290565b808391020590671bc16d674ec80000821215614bc8575b831d90614b99565b8091950194831d90614bc0565b93505093925050020290565b6000199392508015614ac3576ec097ce7bc90715b34b9f10000000000591614b14565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c645768033dd1780914b9711419811261384a57614c5b90600003614c35565b6137a890614ad9565b680a688906bd8affffff81136154b857670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539b575b66ff0000000000008316615293575b65ff00000000008316615193575b64ff00000000831661509b575b63ff0000008316614fab575b62ff00008316614ec3575b61ff008316614de3575b60ff8316614d0c575b02911c60bf031c90565b60808316614dd1575b838316614dbf575b60208316614dad575b60108316614d9b575b60088316614d89575b60048316614d77575b60028316614d65575b6001831615614d02576801000000000000000102831c614d02565b6801000000000000000102831c614d4a565b6801000000000000000302831c614d41565b6801000000000000000602831c614d38565b6801000000000000000b02831c614d2f565b6801000000000000001602831c614d26565b6801000000000000002c02831c614d1d565b6801000000000000005902831c614d15565b6180008316614eb1575b6140008316614e9f575b6120008316614e8d575b6110008316614e7b575b6108008316614e69575b6104008316614e57575b6102008316614e45575b610100831615614cf957680100000000000000b102831c614cf9565b6801000000000000016302831c614e29565b680100000000000002c602831c614e1f565b6801000000000000058c02831c614e15565b68010000000000000b1702831c614e0b565b6801000000000000162e02831c614e01565b68010000000000002c5d02831c614df7565b680100000000000058b902831c614ded565b628000008316614f99575b624000008316614f87575b622000008316614f75575b621000008316614f63575b620800008316614f51575b620400008316614f3f575b620200008316614f2d575b62010000831615614cef576801000000000000b17202831c614cef565b680100000000000162e402831c614f10565b6801000000000002c5c802831c614f05565b68010000000000058b9102831c614efa565b680100000000000b172102831c614eef565b68010000000000162e4302831c614ee4565b680100000000002c5c8602831c614ed9565b6801000000000058b90c02831c614ece565b63800000008316615089575b63400000008316615077575b63200000008316615065575b63100000008316615053575b63080000008316615041575b6304000000831661502f575b6302000000831661501d575b6301000000831615614ce45768010000000000b1721802831c614ce4565b6801000000000162e43002831c614fff565b68010000000002c5c86002831c614ff3565b680100000000058b90c002831c614fe7565b6801000000000b17217f02831c614fdb565b680100000000162e42ff02831c614fcf565b6801000000002c5c85fe02831c614fc3565b68010000000058b90bfc02831c614fb7565b6480000000008316615181575b644000000000831661516f575b642000000000831661515d575b641000000000831661514b575b6408000000008316615139575b6404000000008316615127575b6402000000008316615115575b640100000000831615614cd857680100000000b17217f802831c614cd8565b68010000000162e42ff102831c6150f6565b680100000002c5c85fe302831c6150e9565b6801000000058b90bfce02831c6150dc565b68010000000b17217fbb02831c6150cf565b6801000000162e42fff002831c6150c2565b68010000002c5c8601cc02831c6150b5565b680100000058b90c0b4902831c6150a8565b658000000000008316615281575b65400000000000831661526f575b65200000000000831661525d575b65100000000000831661524b575b650800000000008316615239575b650400000000008316615227575b650200000000008316615215575b65010000000000831615614ccb576801000000b17218355102831c614ccb565b680100000162e430e5a202831c6151f5565b6801000002c5c863b73f02831c6151e7565b68010000058b90cf1e6e02831c6151d9565b680100000b1721bcfc9a02831c6151cb565b68010000162e43f4f83102831c6151bd565b680100002c5c89d5ec6d02831c6151af565b6801000058b91b5bc9ae02831c6151a1565b66800000000000008316615389575b66400000000000008316615377575b66200000000000008316615365575b66100000000000008316615353575b66080000000000008316615341575b6604000000000000831661532f575b6602000000000000831661531d575b6601000000000000831615614cbd5768010000b17255775c0402831c614cbd565b6801000162e525ee054702831c6152fc565b68010002c5cc37da949202831c6152ed565b680100058ba01fb9f96d02831c6152de565b6801000b175effdc76ba02831c6152cf565b680100162f3904051fa102831c6152c0565b6801002c605e2e8cec5002831c6152b1565b68010058c86da1c09ea202831c6152a2565b6780000000000000008316615499575b6740000000000000008316615487575b6720000000000000008316615475575b6710000000000000008316615463575b6708000000000000008316615451575b670400000000000000831661543f575b670200000000000000831661542d575b670100000000000000831615614cae57680100b1afa5abcbed6102831c614cae565b68010163da9fb33356d802831c61540b565b680102c9a3e778060ee702831c6153fb565b6801059b0d31585743ae02831c6153eb565b68010b5586cf9890f62a02831c6153db565b6801172b83c7d517adce02831c6153cb565b6801306fe0a31b7152df02831c6153bb565b5077b504f333f9de6484800000000000000000000000000000006153ab565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558757670de0b6b3a7640000908183101561555057947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d757508051156155ad57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615622575b6155e8575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e056fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = hex"60a034620003b757601f19906001600160401b0390601f6200499e3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c19081620003dd8239608051816139430152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f5a57508063027b674414612f3757806306fdde0314612e72578063081812fc14612e53578063095ea7b314612d5a5780631400ecec14612cba5780631c1cdd4c14612c555780631e99d56914612c3757806323b872dd14612c1f57806340e58ee5146129a1578063425d30dd1461295057806342842e0e1461290057806342966c681461272557806344267570146126fe5780634857501f146126885780634869e12d1461264d5780634cc55e11146121bd57806353b157271461209e5780636352211e1461206e5780636d0cee751461206e57806370a0823114611ffe57806375829def14611f6b578063780a82c814611f1e5780637cad6cd114611e245780637de6b1db14611bfd5780638659c270146118ac578063894e9a0d1461158c5780638f69b993146114f05780639067b677146114a057806395d89b4114611391578063a22cb465146112d4578063a80fc07114611282578063ab167ccc14611138578063ad35efd4146110d6578063b256456914611085578063b88d4fde14610ff8578063b8a3be6614610fc3578063b971302a14610f74578063bc2be1be14610f24578063c156a11d14610a77578063c87b56dd1461095b578063cc364f4814610890578063d4dbd20b1461083e578063d511609f146107f2578063d975dfed146107a6578063e985e9c514610751578063ea5ead1914610729578063eac8f5b8146106d7578063f590c17614610675578063f851a4401461064f5763fdd46d601461025257600080fd5b3461064c57606036600319011261064c576004359061026f613089565b916102786131e6565b92610281613939565b818352600960209181835260ff600160408720015460a81c16156106355783855281835260ff600160408720015460a01c1661061d576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a7576103038961412a565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134dd565b906103b181868401511692826040818351169201511690613220565b161115610532575b848c528252600160408c20015416946103d3818a88614152565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613105565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613105565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d589613995565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60046040517fc61a0e9e000000000000000000000000000000000000000000000000000000008152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461064c578060031936011261064c576001600160a01b036020915416604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760016040836001600160a01b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c5760043590610747613089565b916102788161412a565b503461064c57604036600319011261064c5761076b613073565b6040610775613089565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e160209161412a565b6001600160801b0360405191168152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057604082600292602094526009845220015460801c604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760036040836001600160801b0393602095526009855220015416604051908152f35b503461064c576020908160031936011261064c57600435916108b06134be565b508282526009815260ff600160408420015460a81c16156109445760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361090b85613136565b8452830152604082015261094260405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043561097a81613692565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a6b5780936109ea575b50506109e660405192828493845283019061304e565b0390f35b909192503d8082843e6109fd81846131a8565b8201918381840312610a675780519067ffffffffffffffff821161049c570182601f82011215610a6757805191610a33836131ca565b93610a4160405195866131a8565b83855285848401011161064c575090610a5f9184808501910161302b565b9038806109d0565b5080fd5b604051903d90823e3d90fd5b503461064c57604036600319011261064c57600435610a94613089565b610a9c613939565b81835260099060209082825260ff600160408720015460a81c161561063557838552600382526001600160a01b03918260408720541693843303610f0557610ae38661412a565b906001600160801b039081831680158015610b83575b50505050505081811615610b6b5783610b11916137f4565b90811680610b315760248460405190637e27328960e01b82526004820152fd5b8203610b3b578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b8b613939565b898b5282865260ff600160408d20015460a81c1615610eee57898b5282865260ff600160408d20015460a01c16610ed65788156105f357610ebe57888a52600385528660408b205416918289141580610eae575b610e8a57610bec8a61412a565b8481168311610e585750898b5280865260408b20938260028a87541696015460801c01818111610e445790610c538d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c6f818a8401511692826040818351169201511690613220565b161115610e15575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610cb6818688614152565b604051908152a48033141580610e0b575b610da1575b813314159081610d96575b81610d8b575b50610d1a575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610af9565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d73575b80610ce3565b610d7c90613105565b610d87578538610d6d565b8580fd5b905081141538610cdd565b823b15159150610cd7565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610df7575b5050610ccc565b610e0090613105565b6104a0578338610df0565b50803b1515610cc7565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c77565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610eb88a613995565b15610bdf565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576040826001600160a01b03926020945260098452205416604051908152f35b503461064c57602036600319011261064c5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461064c57608036600319011261064c57611012613073565b61101a613089565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284611049856131ca565b9361105760405195866131a8565b8585523660248783010111610a67578561108296602460209301838801378501015260443591613525565b80f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460b01c166040519015158152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05761110f9061376d565b60405190600581101561112457602092508152f35b602483634e487b7160e01b81526021600452fd5b503461064c5761014036600319011261064c57611153613939565b61115b6134be565b9064ffffffffff80421680845281611171613511565b1661126c575b60e4359082821682036112675701166040830152600435916001600160a01b0391828416809403611267576024359083821680920361126757604435906001600160801b038216809203611267576064359085821680920361064c5750608435918215158093036112675760a4359384151580950361126757604051976111fd89613119565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126757604051916112378361318c565b610104359182168203611267578261125f9260209452610124358482015260e0820152613a7c565b604051908152f35b600080fd5b81611275613511565b8201166020850152611177565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760026040836001600160801b0393602095526009855220015416604051908152f35b503461064c57604036600319011261064c576112ee613073565b60243590811515809203611267576001600160a01b03169081156113605733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c578060031936011261064c5760405190806002549160018360011c9260018516948515611496575b602095868610811461148257858852879493929187908215611460575050600114611406575b50506113f2925003836131a8565b6109e660405192828493845283019061304e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106114485750506113f2935082010138806113e4565b80548389018501528794508693909201918101611430565b92509350506113f294915060ff191682840152151560051b82010138806113e4565b602483634e487b7160e01b81526022600452fd5b93607f16936113be565b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c0576115299061376d565b906005821015908161156a576002831491821561157e575b8215611555575b6020836040519015158152f35b90915061156a57506004602091143880611548565b80634e487b7160e01b602492526021600452fd5b506003831491506000611541565b503461064c57602036600319011261064c57806101606040516115ae81613152565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f16134be565b61014082015201526004358152600960205260ff600160408320015460a81c1615611894576004358152600960205260408120906116bf6002604051936116378561316f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134dd565b6101208301526116d060043561376d565b6005811015611880576101606101c093600264ffffffffff9314611875575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b61177c8d613152565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116ef565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461064c57602080600319360112610a675760043567ffffffffffffffff811161049c576118df9036906004016130d4565b91906118e9613939565b83925b8084106118f7578480f35b611902848284613498565b359361190c613939565b848652600980855260ff90600190828260408b20015460a81c1615611be657878952808752604089208281015460a01c84161561195b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bce5761198c8160005260096020526001600160a01b0360406000205416331490565b15611bae5761199a816136b5565b818a528289526119af600260408c20016134dd565b906001600160801b0395868351168783161015611b9657838c52848b5260408c205460f01c1615611b7e5791818a611a0085898f9a9998966119f68c998387935116613220565b9501511690613220565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b65575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aaa8b8588614152565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b0e575b5050505050506001019291906118ec565b813b15610d8757856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b51575b80808080611afd565b611b5a90613105565b610524578438611b48565b818601600160a01b60ff60a01b19825416179055611a65565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461064c57602080600319360112610a675760043590611c1c613939565b8183526009815260ff600160408520015460a81c1615611e0d57611c3f8261376d565b6005811015611df95760048103611c685760248360405190634a5541ef60e01b82526004820152fd5b60038103611c88576024836040519063fe19f19f60e01b82526004820152fd5b600214611de157611caf8260005260096020526001600160a01b0360406000205416331490565b15611dc2578183526009815260ff604084205460f01c1615611daa57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d52575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d96575b80611d23565b611d9f90613105565b61049c578238611d90565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461064c57602036600319011261064c576004356001600160a01b039081811680910361049c5781835416338103611ef5575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee15760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c05760408264ffffffffff9260209452600a8452205416604051908152f35b503461064c57602036600319011261064c57611f85613073565b9080546001600160a01b0380821693338503611fd7576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461064c57602036600319011261064c576001600160a01b03612020613073565b16801561203d578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c57602036600319011261064c57602061208d600435613692565b6001600160a01b0360405191168152f35b503461064c5761016036600319011261064c576120b9613939565b604051906120c682613119565b6120ce613073565b82526120d8613089565b60208301526120e56131e6565b60408301526001600160a01b03906064358281168103610a67576060840152608435801515810361126757608084015260a43580151581036112675760a084015260603660c319011261064c575060405161213f81613136565b64ffffffffff60c435818116810361126757825260e435818116810361126757602083015261010435908116810361126757604082015260c083015260406101231936011261126757604051916121958361318c565b610124359182168203611267578261125f9260209452610144358482015260e0820152613a7c565b503461064c57604036600319011261064c5767ffffffffffffffff60043581811161049c576121f09036906004016130d4565b90916024359081116104a05761220a9036906004016130d4565b612212613939565b80830361261657845b838110612226578580f35b612231818587613498565b359061223e818688613498565b35875260036020526001600160a01b0360408820541661225f828587613498565b35906001600160801b038216820361126757612279613939565b838952600960205260ff600160408b20015460a81c161561063557838952600960205260ff600160408b20015460a01c1661061d5780156105f3576001600160801b038216156125fe5783895260036020526001600160a01b0360408a2054169182821415806125ee575b6125ca576122f18561412a565b6001600160801b0381166001600160801b0383161161259a5750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123828c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123a68160208401511692826040818351169201511690613220565b161115612569575b86855260096020526001600160a01b036001604087200154166123db6001600160801b0384168583614152565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061255f575b6124f5575b8333141590816124ea575b816124df575b5061246d575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161221b565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c7575b8080612436565b6124d090613105565b6124db5786386124c0565b8680fd5b905083141538612430565b843b1515915061242a565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161254b575b505061241f565b61255490613105565b610524578438612544565b50803b151561241a565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123ae565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f885613995565b156122e4565b6024846040519063d2aabcd960e01b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461064c57602036600319011261064c5760ff6001604060043593848152600960205220015460a81c16156106c0576107e16020916139fe565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57806126c38361376d565b926005841015611880576002602094036126e4575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126d8565b503461064c578060031936011261064c5760206001600160a01b0360085416604051908152f35b503461064c57602080600319360112610a675760043590612744613939565b8183526009815260ff600160408520015460a81c1615611e0d578183526009815260ff600160408520015460a01c16156128cf5761278182613995565b15611dc25781600052600381526001600160a01b0380604060002054166009835260ff60016040600020015460b01c161590816128c5575b50806128bd575b6128a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79083600052600383526040600020541691821592831561286a575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612852575080f35b60249060405190637e27328960e01b82526004820152fd5b61288b85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612800565b60248360405190630da9b01360e01b82526004820152fd5b5060006127c0565b90501515386127b9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461064c5761290f3661309f565b60405191602083019383851067ffffffffffffffff86111761293a5761108294604052858452613525565b634e487b7160e01b600052604160045260246000fd5b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057600160408360ff93602095526009855220015460a01c166040519015158152f35b503461064c576020908160031936011261064c57600435906129c1613939565b81815260099283815260ff600160408420015460a81c16156109445782825283815260408220600181015460a01c60ff1615612a0f5760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bce57612a3a8160005260096020526001600160a01b0360406000205416331490565b15611bae57612a48816136b5565b93818452808352612a5e600260408620016134dd565b916001600160801b0393848451168588161015611de15781865282815260ff604087205460f01c1615611daa57612aac878683612aa28a9b838a9c9b9c5116613220565b9701511690613220565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c05575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b388c8487614152565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bb4578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bf6575b81818080808480f35b612bff90613105565b81612bed565b60018101600160a01b60ff60a01b19825416179055612af1565b503461064c57611082612c313661309f565b9161324f565b503461064c578060031936011261064c576020600754604051908152f35b503461064c57602036600319011261064c57600435808252600960205260ff600160408420015460a81c16156106c057612c8e9061376d565b90600582101561156a5760208215838115612caf575b506040519015158152f35b600191501482612ca4565b503461064c57602036600319011261064c5760043590818152600960205260ff600160408320015460a81c1615611e0d57602091604082828152600985522060ff815460f01c1680612d48575b612d1f575b50506001600160801b0360405191168152f35b612d4192506001600160801b036002612d3b92015416916136b5565b90613220565b3880612d0c565b5060ff600182015460a01c1615612d07565b503461064c57604036600319011261064c57612d74613073565b602435612d8081613692565b33151580612e40575b80612e16575b612de65781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612d8f565b50336001600160a01b0382161415612d89565b503461064c57602036600319011261064c57602061208d6004356131fc565b503461064c578060031936011261064c576040519080600191600154928360011c9260018516948515612f2d575b602095868610811461148257858852879493929187908215611460575050600114612ed35750506113f2925003836131a8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f155750506113f2935082010138806113e4565b80548389018501528794508693909201918101612efd565b93607f1693612ea0565b503461064c578060031936011261064c57602060405167016345785d8a00008152f35b905034610a67576020366003190112610a67576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613001575b8115612fd7575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fd0565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fc9565b60005b83811061303e5750506000910152565b818101518382015260200161302e565b906020916130678151809281855285808601910161302b565b601f01601f1916010190565b600435906001600160a01b038216820361126757565b602435906001600160a01b038216820361126757565b6060906003190112611267576001600160a01b0390600435828116810361126757916024359081168103611267579060443590565b9181601f840112156112675782359167ffffffffffffffff8311611267576020808501948460051b01011161126757565b67ffffffffffffffff811161293a57604052565b610100810190811067ffffffffffffffff82111761293a57604052565b6060810190811067ffffffffffffffff82111761293a57604052565b610180810190811067ffffffffffffffff82111761293a57604052565b610140810190811067ffffffffffffffff82111761293a57604052565b6040810190811067ffffffffffffffff82111761293a57604052565b90601f8019910116810190811067ffffffffffffffff82111761293a57604052565b67ffffffffffffffff811161293a57601f01601f191660200190565b604435906001600160801b038216820361126757565b61320581613692565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161323957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561348057600091848352602091600383526040928284862054166009825260ff6001868820015460b01c16159081613476575b508061346e575b6134575786855260038152828486205416948733151593846133a7575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761336f575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133415750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339082600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132dd565b91929380915090613416575b156133c157908783926132b4565b8488876133de576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b50338614801561343b575b806133b357508782526005835233848684205416146133b3565b5085825260068352848220338352835260ff8583205416613421565b602487855190630da9b01360e01b82526004820152fd5b506001613297565b9050151538613290565b6024604051633250574960e11b815260006004820152fd5b91908110156134a85760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134cb82613136565b60006040838281528260208201520152565b906040516134ea81613136565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036112675790565b919061353282828561324f565b803b61353f575b50505050565b61359b6001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061304e565b03906020816000938185885af190829082613631575b50506135e857826135c06140fa565b80519190826135e15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613619575038808080613539565b60249060405190633250574960e11b82526004820152fd5b909192506020813d60201161368a575b8161364e602093836131a8565b81010312610a675751907fffffffff000000000000000000000000000000000000000000000000000000008216820361064c57509038806135b1565b3d9150613641565b8060005260036020526001600160a01b0360406000205416908115612852575090565b600090808252600a60205264ffffffffff918260408220541642106137675760096020526040812092835490808260c81c169182421015613751576137069394955060a01c168091039042036142f6565b9082815260096020526001600160801b039261372c8460026040852001541680946143d6565b9283116137395750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c16600014613794575050600490565b805460f81c6137ed575460a01c64ffffffffff1642106137e7576137b7816136b5565b9060005260096020526001600160801b0380600260406000200154169116106000146137e257600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b036040958187842054166009855260ff6001898620015460b01c1615908161392f575b5080613924575b61390d579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138d5575b1692836138bf575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b838752600488528087206001815401905561389b565b6138f686600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613893565b602486885190630da9b01360e01b82526004820152fd5b508181161515613832565b905015153861382b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396b57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139da575b505082156139c857505090565b9091506139d533926131fc565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139bb565b806000526009602052613a1760026040600020016134dd565b816000526009602052604060002060ff600182015460a01c16600014613a4a57506001600160801b039150602001511690565b5460f81c613a5f5750613a5c906136b5565b90565b613a5c91506001600160801b036040818351169201511690613220565b90613a9d6001600160801b03604084015116602060e08501510151906141ae565b916001600160801b0383511660c082015190156140d05764ffffffffff815116156140a65764ffffffffff81511690604081019164ffffffffff8351169081811015614066575050602081019064ffffffffff8251169081151580614054575b61401357505064ffffffffff90511664ffffffffff8251169081811015613fd357505064ffffffffff8042169151169081811015613f93575050600754926001600160801b0381511660405190613b5382613136565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb58861316f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dad84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f75575b50600184016007556001600160a01b03602083015116801561348057613dfd856001600160a01b03926137f4565b16613f4457613e286001600160a01b036060840151166001600160801b038351169030903390614287565b6001600160801b0360208201511680613f15575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0c6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3e906001600160a01b036060850151166001600160a01b0360e08601515116903390614287565b38613e3c565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dcf565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b516040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b508164ffffffffff8251161015613afd565b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614125573d9061410b826131ca565b9161411960405193846131a8565b82523d6000602084013e565b606090565b613a5c90614137816139fe565b90600052600960205260026040600020015460801c90613220565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ac916141a76064836131a8565b614485565b565b919091604051906141be8261318c565b600091828152826020820152936001600160801b03928383169182156142685767016345785d8a000080821161423157506141fa8591846143d6565b166020870192818452111561421d5750908261421892511690613220565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061427c8261318c565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff84111761293a576141ac92604052614485565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143b2578285101561437657908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c0570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447457670de0b6b3a7640000908183101561443d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b0600080836020829551910182875af16144a96140fa565b9084614521565b9081519182151592836144f9575b5050506144c85750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a6757602001519081159182150361064c57503880806144be565b90614560575080511561453657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145ab575b614571575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561456956fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 7f8e13dc3..53bbdf28a 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -240,13 +240,14 @@ contract SablierV2LockupDynamic is currentSegmentTimestamp = segments[index].timestamp; uint40 previousTimestamp; - if (index > 0) { - // When the current segment's index is greater than or equal to 1, it implies that the segment is not + if (index == 0) { + // When the current segment's index is equal to 0, the current segment is the first, so use the start + // time as the previous timestamp. + previousTimestamp = stream.startTime; + } else { + // Otherwise, when the current segment's index is greater than 0, it implies that the segment is not // the first. In this case, use the previous segment's timestamp. previousTimestamp = segments[index - 1].timestamp; - } else { - // Otherwise, the current segment is the first, so use the start time as the previous timestamp. - previousTimestamp = stream.startTime; } // Calculate how much time has passed since the segment started, and the total time of the segment. From 76e29fee33befaeb54a82473c28cf182e6f8855d Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 2 Apr 2024 22:42:32 +0100 Subject: [PATCH 079/132] test: integration tests for withdraw hooks (#873) --- .../lockup/withdraw-hooks/withdrawHooks.t.sol | 284 ++++++++++++++++++ .../lockup/withdraw-hooks/withdrawHooks.tree | 21 ++ .../concrete/lockup/withdraw/withdraw.t.sol | 8 - .../shared/lockup-dynamic/LockupDynamic.t.sol | 15 + .../shared/lockup-linear/LockupLinear.t.sol | 15 + .../lockup-tranched/LockupTranched.t.sol | 15 + test/integration/shared/lockup/Lockup.t.sol | 14 + test/integration/shared/lockup/withdraw.t.sol | 8 + test/utils/Assertions.sol | 1 + 9 files changed, 373 insertions(+), 8 deletions(-) create mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol create mode 100644 test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol new file mode 100644 index 000000000..6261abcbf --- /dev/null +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: UNLICENSED +// solhint-disable max-line-length +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; +import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; + +import { Integration_Test } from "../../../Integration.t.sol"; +import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; + +abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, Withdraw_Integration_Shared_Test { + function setUp() public virtual override(Integration_Test, Withdraw_Integration_Shared_Test) { + Withdraw_Integration_Shared_Test.setUp(); + } + + modifier givenDifferentSenderAndRecipient() { + _; + } + + function test_WithdrawHooks_CallerUnknown() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + address unknownCaller = address(0xCAFE); + + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make `unknownCaller` the caller in this test. + changePrank({ msgSender: unknownCaller }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, unknownCaller, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerApprovedOperator() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodRecipient) }); + lockup.approve({ to: users.operator, tokenId: streamId }); + + // Make the operator the caller in this test. + changePrank({ msgSender: users.operator }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, users.operator, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerSender() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make the sender the caller in this test. + changePrank({ msgSender: address(goodSender) }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 1 call to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Expect 0 calls to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodRecipient), withdrawAmount) + ), + count: 0 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + function test_WithdrawHooks_CallerRecipient() + external + givenSenderContract + givenRecipientContract + givenDifferentSenderAndRecipient + { + // Create the stream with sender and recipient as contracts. + uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + + // Make the recipient the caller in this test. + changePrank({ msgSender: address(goodRecipient) }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 0 calls to the recipient hook. + vm.expectCall({ + callee: address(goodRecipient), + data: abi.encodeCall( + ISablierV2Recipient.onLockupStreamWithdrawn, + (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) + ), + count: 0 + }); + + // Expect 1 call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + } + + modifier givenSameSenderAndRecipient() { + _; + } + + function test_WithdrawHooks_SenderHook_CallerUnknown() external givenSenderContract givenSameSenderAndRecipient { + address unknownCaller = address(0xCAFE); + + // Create the stream with recipient which is same as the sender contract. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Make unknownCaller the caller in this test. + changePrank({ msgSender: unknownCaller }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodSender), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } + + function test_WithdrawHooks_SenderHook_CallerApprovedOperator() + external + givenSenderContract + givenSameSenderAndRecipient + { + // Create the stream with recipient which is same as the sender contract. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodSender) }); + lockup.approve({ to: users.operator, tokenId: streamId }); + + // Make the operator the caller in this test. + changePrank({ msgSender: users.operator }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect a call to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodSender), withdrawAmount) + ), + count: 1 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } + + function test_WithdrawHooks_SenderHook_CallerSender() external givenSenderContract givenSameSenderAndRecipient { + // Create the stream with the sender as the recipient. + uint256 streamId = createDefaultStreamToSender(address(goodSender)); + + // Approve the operator to handle the stream. + changePrank({ msgSender: address(goodSender) }); + + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + + // Expect 0 calls to the sender hook. + vm.expectCall({ + callee: address(goodSender), + data: abi.encodeCall( + ISablierV2Sender.onLockupStreamWithdrawn, + (streamId, address(goodSender), address(goodSender), withdrawAmount) + ), + count: 0 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + } +} diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree new file mode 100644 index 000000000..79a896aa2 --- /dev/null +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree @@ -0,0 +1,21 @@ +withdrawHooks.t.sol +├── given the recipient is different than the sender +│ ├── when the caller is unknown +│ │ ├── it should make one hook call to the sender +│ │ └── it should make one hook call to the recipient +│ ├── when the caller is an approved third party +│ │ ├── it should make one hook call to the sender +│ │ └── it should make one hook call to the recipient +│ ├── when the caller is the sender +│ │ ├── it should not make any hook call to the sender +│ │ └── it should make one hook call to the recipient +│ └── when the caller is the recipient +│ ├── it should make one hook call to the sender +│ └── it should not make any hook call to the recipient +└── given the recipient is same as the sender + ├── when the caller is unknown + │ └── it should make one hook call to the sender + ├── when the caller is an approved third party + │ └── it should make one hook call to the sender + └── when the caller is the sender + └── it should not make any hook call to the sender diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 1a470c742..55d0d05c8 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -197,10 +197,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerRecipient(defaultStreamId, users.sender); } - modifier givenSenderContract() { - _; - } - function test_Withdraw_SenderDoesNotImplementHook() external whenNotDelegateCalled @@ -459,10 +455,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr test_Withdraw_CallerSender(defaultStreamId, users.recipient); } - modifier givenRecipientContract() { - _; - } - function test_Withdraw_RecipientDoesNotImplementHook() external whenNotDelegateCalled diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index b67bf3aa4..08ee66844 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -147,4 +147,19 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh params.totalAmount = totalAmount; streamId = lockupDynamic.createWithTimestamps(params); } + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + override + returns (uint256 streamId) + { + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + params.recipient = recipient; + streamId = lockupDynamic.createWithTimestamps(params); + } } diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 1fe86adbf..eed455052 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -113,4 +113,19 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha params.totalAmount = totalAmount; streamId = lockupLinear.createWithTimestamps(params); } + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + override + returns (uint256 streamId) + { + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + params.recipient = recipient; + streamId = lockupLinear.createWithTimestamps(params); + } } diff --git a/test/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/integration/shared/lockup-tranched/LockupTranched.t.sol index 69725a5e0..e9413d848 100644 --- a/test/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -156,4 +156,19 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S params.totalAmount = totalAmount; streamId = lockupTranched.createWithTimestamps(params); } + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + override + returns (uint256 streamId) + { + LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.sender = sender; + params.recipient = recipient; + streamId = lockupTranched.createWithTimestamps(params); + } } diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 3d3b73633..6ee2a4d8e 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -41,6 +41,11 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal virtual returns (uint256 streamId); + /// @dev Creates the default stream with recipient as the sender. + function createDefaultStreamToSender(address sender) internal virtual returns (uint256 streamId) { + return createDefaultStreamWithUsers(sender, sender); + } + /// @dev Creates the default stream with the provided address. function createDefaultStreamWithAsset(IERC20 asset) internal virtual returns (uint256 streamId); @@ -61,4 +66,13 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the provided total amount. function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal virtual returns (uint256 streamId); + + /// @dev Creates the default stream with the provided sender and recipient. + function createDefaultStreamWithUsers( + address recipient, + address sender + ) + internal + virtual + returns (uint256 streamId); } diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index ac9dcfced..11357aefb 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -19,6 +19,14 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } + modifier givenRecipientContract() { + _; + } + + modifier givenSenderContract() { + _; + } + modifier givenStreamNotDepleted() { vm.warp({ newTimestamp: defaults.START_TIME() }); _; diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 2dea51dab..a174981dc 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable event-name-camelcase pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; From 660f06c7e6b6d849d97c704e5c3ea509a87e52fb Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 9 Apr 2024 16:10:43 +0100 Subject: [PATCH 080/132] ci: pass CODECOV_TOKEN --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c849781c2..aff2f0071 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,8 @@ jobs: coverage: needs: ["lint", "build"] + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" with: match-path: "test/{integration,unit}/**/*.sol" From bbe1a7b0b65e6a433f5ae14bea1b31a7f20e2d94 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 9 Apr 2024 16:10:43 +0100 Subject: [PATCH 081/132] ci: pass CODECOV_TOKEN --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec055182b..3400c14ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,8 @@ jobs: coverage: needs: ["lint", "build"] + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" with: match-path: "test/{integration,unit}/**/*.sol" From ca85b7e5569aa1787c1affde9fd496f6f4734ccc Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 9 Apr 2024 16:14:38 +0100 Subject: [PATCH 082/132] ci: upgrade actions/upload-artifact --- .github/workflows/run-smtchecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-smtchecker.yml b/.github/workflows/run-smtchecker.yml index 89a68cafb..9df7b5718 100644 --- a/.github/workflows/run-smtchecker.yml +++ b/.github/workflows/run-smtchecker.yml @@ -16,7 +16,7 @@ jobs: run: "FOUNDRY_PROFILE=smt forge build > smtchecker-report.txt" - name: "Store the report as an artifact" - uses: "actions/upload-artifact@v3" + uses: "actions/upload-artifact@v4" with: name: smtchecker-report path: "smtchecker-report.txt" From e9fcd6d3a805ba0847f412ba378d9fe2ee63109a Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 10 Apr 2024 00:50:05 +0300 Subject: [PATCH 083/132] Feedback from PRB on V2.2 (#883) * docs: improve wording in NatSpec chore: improve wording comments chore: misc improvements and renames docs: capitalize ID refactor: improve variable names refactor: separate max segment and tranche counts refactor: use for loop instead of while * build: bump OpenZeppelin to v5.0.2 * docs: improve writing in NatSpec perf: optimize "_update" by testing "_isTransferable" last test: apply "inheritdoc" test: define "withdrawAmount" once test: improve function names test: improve writing in comments test: set the license to "UNLICENSED" * refactor: rename "streamingModel" to "sablierModel" docs: improve writing in NatSpec refactor: rename "sablierAddress" to "sablierStringified" * refactor: rename internal create function * chore: singular Check, Effect, Interaction docs: improve writing in custom errors' NatSpec * perf: close #878 docs: improve writing in NatSpec test: apply "seconds" keyword * refactor: reorder checks chore: improve writing in comments test: bring back test in "createWithDurations" test: close #880 test: fuzz cliff time as zero test: improve BTs and associated modifiers * test: remove unused import * test: include map symbol test for lockup tranched docs: _create in NatSpec * revert: bring back GPL V3 license in mocks chore: fix segments reference fix: mistaken "cliffs" array * refactor: update precompiles * test: reuse "createWithTimestamps" modifiers * test: revert max counts to 500 * test: use lockup object * style: correct bad formated natspec * refactor: rename "currentTime" to "blockTimestamp" docs: improve wording in comments perf: use "unchecked" for tranche calculations refactor: rename variables * docs: improve writing in NatSpec * refactor: order functions and fields alphabetically * refactor: rename variable * docs: capitalize IDs chore: update "filter_paths" docs: improve writing in comments refactor: include "streamId" in "SablierV2Lockup_WithdrawToZeroAddress" refactor: alphabetical order * build: bump sphinx * test: remove ERC721Mock and use forge mock * test: update precompiles * chore: say "block timestamp" in comments * refactor: update gas snapshot test: replace "maxUint40" with "maxOfThree" * chore: add trailing slash * build: bump PRBMath --------- Co-authored-by: smol-ninja Co-authored-by: andreivladbrg --- .gas-snapshot | 1129 +++++++++-------- .solhint.json | 2 +- bun.lockb | Bin 308049 -> 306637 bytes foundry.toml | 6 +- package.json | 8 +- precompiles/Precompiles.sol | 19 +- remappings.txt | 2 +- script/Base.s.sol | 31 +- script/DeployCore.s.sol | 8 +- script/DeployCore2.s.sol | 8 +- script/DeployDeterministicCore.s.sol | 8 +- script/DeployDeterministicCore2.s.sol | 8 +- script/DeployDeterministicLockupDynamic.s.sol | 6 +- script/DeployDeterministicLockupLinear.s.sol | 4 +- .../DeployDeterministicLockupTranched.s.sol | 6 +- script/DeployDeterministicNFTDescriptor.s.sol | 4 +- script/DeployLockupDynamic.s.sol | 6 +- script/DeployLockupLinear.s.sol | 4 +- script/DeployLockupTranched.s.sol | 6 +- script/DeployNFTDescriptor.s.sol | 4 +- script/GenerateSVG.s.sol | 6 +- slither.config.json | 3 +- src/SablierV2LockupDynamic.sol | 75 +- src/SablierV2LockupLinear.sol | 57 +- src/SablierV2LockupTranched.sol | 64 +- src/SablierV2NFTDescriptor.sol | 36 +- src/abstracts/Adminable.sol | 2 +- src/abstracts/SablierV2Lockup.sol | 96 +- src/interfaces/ISablierV2Lockup.sol | 72 +- src/interfaces/ISablierV2LockupDynamic.sol | 30 +- src/interfaces/ISablierV2LockupLinear.sol | 24 +- src/interfaces/ISablierV2LockupTranched.sol | 30 +- src/interfaces/ISablierV2NFTDescriptor.sol | 2 +- src/interfaces/hooks/ISablierV2Recipient.sol | 8 +- src/interfaces/hooks/ISablierV2Sender.sol | 4 +- src/libraries/Errors.sol | 13 +- src/libraries/Helpers.sol | 251 ++-- src/libraries/NFTSVG.sol | 10 +- src/types/DataTypes.sol | 115 +- test/Base.t.sol | 8 +- test/fork/LockupDynamic.t.sol | 10 +- test/fork/LockupLinear.t.sol | 48 +- test/fork/LockupTranched.t.sol | 10 +- .../concrete/lockup-dynamic/constructor.t.sol | 6 +- .../createWithDurations.t.sol | 8 +- .../createWithDurations.tree | 2 +- .../createWithTimestamps.t.sol | 6 +- .../createWithTimestamps.tree | 4 +- .../lockup-dynamic/get-range/getRange.tree | 4 +- .../get-segments/getSegments.tree | 4 +- .../lockup-dynamic/get-stream/getStream.tree | 4 +- .../lockup-dynamic/token-uri/tokenURI.t.sol | 2 +- .../createWithDurations.t.sol | 34 +- .../createWithDurations.tree | 15 +- .../createWithTimestamps.t.sol | 31 +- .../createWithTimestamps.tree | 13 +- .../get-cliff-time/getCliffTime.tree | 4 +- .../lockup-linear/get-range/getRange.tree | 4 +- .../lockup-linear/get-stream/getStream.tree | 4 +- .../lockup-linear/token-uri/tokenURI.t.sol | 2 +- .../lockup-tranched/constructor.t.sol | 6 +- .../createWithDurations.t.sol | 8 +- .../createWithDurations.tree | 2 +- .../createWithTimestamps.t.sol | 7 +- .../createWithTimestamps.tree | 4 +- .../lockup-tranched/get-range/getRange.tree | 4 +- .../lockup-tranched/get-stream/getStream.tree | 4 +- .../get-tranches/getTranches.tree | 4 +- .../lockup-tranched/token-uri/tokenURI.t.sol | 2 +- .../concrete/lockup/burn/burn.tree | 4 +- .../cancel-multiple/cancelMultiple.tree | 6 +- .../concrete/lockup/cancel/cancel.tree | 5 +- .../concrete/lockup/get-asset/getAsset.tree | 4 +- .../getDepositedAmount.tree | 4 +- .../lockup/get-end-time/getEndTime.tree | 4 +- .../lockup/get-recipient/getRecipient.tree | 4 +- .../getRefundedAmount.tree | 4 +- .../concrete/lockup/get-sender/getSender.tree | 4 +- .../lockup/get-start-time/getStartTime.tree | 4 +- .../getWithdrawnAmount.tree | 4 +- .../lockup/is-cancelable/isCancelable.tree | 4 +- .../concrete/lockup/is-cold/isCold.tree | 4 +- .../lockup/is-depleted/isDepleted.tree | 4 +- .../concrete/lockup/is-stream/isStream.tree | 4 +- .../is-transferable/isTransferable.tree | 4 +- .../concrete/lockup/is-warm/isWarm.tree | 4 +- .../refundableAmountOf.tree | 4 +- .../concrete/lockup/renounce/renounce.tree | 4 +- .../concrete/lockup/status-of/statusOf.tree | 4 +- .../streamed-amount-of/streamedAmountOf.tree | 4 +- .../lockup/was-canceled/wasCanceled.tree | 4 +- .../lockup/withdraw-hooks/withdrawHooks.t.sol | 69 +- .../lockup/withdraw-hooks/withdrawHooks.tree | 2 +- .../withdrawMaxAndTransfer.tree | 4 +- .../withdraw-multiple/withdrawMultiple.tree | 6 +- .../concrete/lockup/withdraw/withdraw.t.sol | 2 +- .../concrete/lockup/withdraw/withdraw.tree | 4 +- .../withdrawableAmountOf.tree | 4 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 26 +- .../lockup-dynamic/createWithDurations.t.sol | 6 +- .../lockup-dynamic/createWithTimestamps.t.sol | 9 +- .../lockup-dynamic/streamedAmountOf.t.sol | 13 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 14 +- .../lockup-linear/createWithDurations.t.sol | 10 +- .../lockup-linear/createWithTimestamps.t.sol | 55 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 6 +- .../lockup-linear/withdrawableAmountOf.t.sol | 14 +- .../lockup-tranched/createWithDurations.t.sol | 6 +- .../createWithTimestamps.t.sol | 9 +- .../lockup-tranched/streamedAmountOf.t.sol | 6 +- .../withdrawableAmountOf.t.sol | 14 +- test/integration/fuzz/lockup/cancel.t.sol | 2 +- .../fuzz/lockup/cancelMultiple.t.sol | 2 +- test/integration/fuzz/lockup/withdraw.t.sol | 2 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 24 +- .../lockup-dynamic/createWithTimestamps.t.sol | 68 - .../shared/lockup-linear/LockupLinear.t.sol | 24 +- .../lockup-linear/createWithDurations.t.sol | 24 - .../lockup-linear/createWithTimestamps.t.sol | 52 - .../lockup-tranched/LockupTranched.t.sol | 22 +- .../lockup-tranched/createWithDurations.t.sol | 28 - test/integration/shared/lockup/Lockup.t.sol | 10 +- .../createWithDurations.t.sol | 18 +- .../createWithTimestamps.t.sol | 70 +- test/invariant/Lockup.t.sol | 2 +- test/invariant/LockupLinear.t.sol | 2 +- .../handlers/LockupDynamicCreateHandler.sol | 4 +- .../handlers/LockupDynamicHandler.sol | 2 +- test/invariant/handlers/LockupHandler.sol | 4 +- .../handlers/LockupLinearCreateHandler.sol | 25 +- .../handlers/LockupLinearHandler.sol | 2 +- .../handlers/LockupTranchedCreateHandler.sol | 4 +- .../handlers/LockupTranchedHandler.sol | 2 +- test/invariant/stores/LockupStore.sol | 4 +- test/mocks/NFTDescriptorMock.sol | 15 +- test/mocks/Noop.sol | 2 +- test/mocks/erc721/ERC721Mock.sol | 8 - .../nft-descriptor/generateName.t.sol | 4 +- .../concrete/nft-descriptor/generateSVG.t.sol | 12 +- test/utils/Assertions.sol | 38 +- test/utils/Calculations.sol | 46 +- test/utils/Defaults.sol | 5 +- test/utils/DeployOptimized.sol | 7 +- test/utils/Fuzzers.sol | 94 +- test/utils/Precompiles.t.sol | 6 +- test/utils/Utils.sol | 12 + 146 files changed, 1674 insertions(+), 1773 deletions(-) delete mode 100644 test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol delete mode 100644 test/integration/shared/lockup-linear/createWithDurations.t.sol delete mode 100644 test/integration/shared/lockup-linear/createWithTimestamps.t.sol delete mode 100644 test/integration/shared/lockup-tranched/createWithDurations.t.sol rename test/integration/shared/{lockup-dynamic => lockup}/createWithDurations.t.sol (54%) rename test/integration/shared/{lockup-tranched => lockup}/createWithTimestamps.t.sol (54%) delete mode 100644 test/mocks/erc721/ERC721Mock.sol diff --git a/.gas-snapshot b/.gas-snapshot index 78dea1dae..23980f0ec 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,588 +1,589 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89934) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80731) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80762) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 81871) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11317) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90162) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14278) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19536) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19551) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 92131) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82942) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82973) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 84085) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89728) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80566) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80555) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 81703) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11307) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90105) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14290) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19526) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19475) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 91971) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82804) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82793) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 83947) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11293) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 82872) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14254) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14276) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19512) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19527) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100990) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91801) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91832) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 92960) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19461) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100802) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91635) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91624) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 92794) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11337) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89982) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14298) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90032) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14320) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19556) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19571) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 815232) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6329) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32142) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 835114) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12417) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78395) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326410) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 918387) -CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 1175383, ~: 1174865) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 595097) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19505) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 825543) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6315) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32135) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 834301) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12422) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78418) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326169) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 917699) +CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1182497, ~: 1186661) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 605488) CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6332) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34306) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 636392) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12414) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80403) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254607) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 719687) -CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 861197, ~: 863450) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 770735) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34328) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 635517) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12436) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80425) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254338) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 718901) +CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 871389, ~: 873499) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 781606) CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6354) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41696) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934828) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12436) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87796) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343455) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028867) -CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 5, μ: 1175542, ~: 1173622) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 371699) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 356833) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97011) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 358721) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357400) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 71443) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11314) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86956) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63201) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26741) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246730) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 440408, ~: 440715) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 71792, ~: 71598) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 276919) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262068) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 79360) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 263946) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 262635) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 73435) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41710) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934117) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12458) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87800) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343272) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028209) +CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1187346, ~: 1189529) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 374152) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 357307) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97679) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 359190) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357874) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 72695) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11309) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86904) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63165) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26736) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246553) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 441056, ~: 442191) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 73280, ~: 73354) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 279422) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262552) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 80064) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 264430) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 263119) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 74751) Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11298) Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79680) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65441) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65418) Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 28901) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192902) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 317991, ~: 318255) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 73922, ~: 73871) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 360534) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 345630) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 86746) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 347552) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346197) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 80881) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192700) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 318219, ~: 319610) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 75350, ~: 75556) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 363234) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 346311) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 87493) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 348233) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346878) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 82179) Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11342) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86790) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74272) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36313) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273818) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 5, μ: 404148, ~: 404572) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 5, μ: 81368, ~: 81317) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5026066) -Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3890433) -Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4081319) -CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 345377) -CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 5, μ: 5491601, ~: 7294034) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 273812) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 5, μ: 272460, ~: 272184) -CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 375613) -CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 5, μ: 5587007, ~: 6183306) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 338393) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 344814) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 38819) -CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 5, μ: 3746257, ~: 3891426) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 272572) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 279015) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_CliffTimeZero() (gas: 228453) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 33005) -CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 5, μ: 358201, ~: 362647) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 365732) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 372087) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41674) -CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 5, μ: 3607120, ~: 3725226) -GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13242) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 276169) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) -GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 224871) -GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11969) -GetAsset_LockupTranched_Integration_Concrete_Test:test_GetAsset() (gas: 301708) -GetAsset_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 225459) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11436) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 279054) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11668) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 227708) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11634) -GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 304615) -GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11690) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 278874) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 227598) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 304457) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11612) -GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 278255) -GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13067) -GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 227888) -GetRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13251) -GetRange_LockupTranched_Integration_Concrete_Test:test_GetRange() (gas: 303751) -GetRange_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13067) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 12464) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67739) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11456) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 12436) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69950) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11428) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 12464) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78809) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11456) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 311270) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 301075) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 306305) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306298) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 345790) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 347632) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 258243) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 247789) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 253019) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253012) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289238) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 290999) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11932) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 339855) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 326614) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 331844) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 331837) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369129) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 370938) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283695) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13744) -GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 275931) -GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11800) -GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 224627) -GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11772) -GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 301470) -GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11800) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 279116) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 227818) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11765) -GetStartTime_LockupTranched_Integration_Concrete_Test:test_GetStartTime() (gas: 304655) -GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 264782) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52545) -GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15581) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 37598) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 42180) -GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14337) -GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream() (gas: 291442) -GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 57205) -GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15565) -GetTranches_LockupTranched_Integration_Concrete_Test:test_GetTranches() (gas: 310185) -GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13497) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 355530) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304291) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 358827, ~: 359251) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 305919, ~: 305643) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 274898) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253005) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11932) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 278393, ~: 278657) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 254633, ~: 254357) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356428) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 329830) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11954) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 5, μ: 359942, ~: 360187) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 5, μ: 331320, ~: 331182) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 481194) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 304629) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 295851) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11269) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 382141) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 253537) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 244594) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11285) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable() (gas: 530457) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 331729) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 321418) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11294) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 344613) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311043) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299108) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 304895) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 321223) -IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11552) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288108) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258068) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 247874) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 253826) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 254340) -IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11590) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 367998) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 339679) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 324698) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332018) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 332495) -IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11599) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 310426) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 295220) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11181) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 257422) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 243957) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11194) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted() (gas: 339033) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 320781) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11203) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 295557) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8510) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 244299) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8526) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 321101) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 8513) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 295700) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11642) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 481113) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 244459) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11677) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 382091) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 321261) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11664) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 530370) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344120) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 310524) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 298512) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 304478) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 320675) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11090) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 287615) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 257544) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 247273) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 253409) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 253787) -IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11128) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 367461) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 339111) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 324053) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 331557) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 331898) -IsWarm_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11093) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 17279) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16907) -MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 911419) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 310510) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304381) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 304352) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311251) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344054) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347259) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 488812) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11129) -RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 44041, ~: 30163) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 257501) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253088) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 253253) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 254718) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 287520) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 290644) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 389772) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86840) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74221) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36305) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273654) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 405987, ~: 406220) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 82750, ~: 82693) +Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5056466) +Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3903481) +Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4104734) +CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 356999) +CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 50, μ: 4078448, ~: 3524013) +CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 286244) +CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 281828, ~: 284643) +CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 387388) +CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 50, μ: 4592175, ~: 4807073) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 350001) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 356422) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 38801) +CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 50, μ: 4240375, ~: 3897903) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 284891) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 291246) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_StartTimeLessThanEndTime() (gas: 242528) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 33024) +CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 50, μ: 397470, ~: 409218) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 377346) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 383767) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41670) +CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 50, μ: 4246517, ~: 4719143) +GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 16028) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 279107) +GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12005) +GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 227792) +GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) +GetAsset_LockupTranched_Integration_Concrete_Test:test_GetAsset() (gas: 304673) +GetAsset_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12013) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 228432) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11413) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 282044) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11637) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 230681) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) +GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 307632) +GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11667) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 281864) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11537) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 230571) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11545) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 307474) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11589) +GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 278092) +GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13036) +GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 227708) +GetRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13228) +GetRange_LockupTranched_Integration_Concrete_Test:test_GetRange() (gas: 303615) +GetRange_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13044) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 15675) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67651) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11436) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 15655) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69889) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11416) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 15683) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78720) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11444) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 311818) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 301586) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 306861) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306854) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 346255) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 348111) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11935) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 258782) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 248283) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 253558) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253551) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289733) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 291516) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11921) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 340410) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 327152) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 332427) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 332420) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369718) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 371537) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11943) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283532) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13713) +GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 278892) +GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11769) +GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 227571) +GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11749) +GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 304458) +GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11777) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 282061) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11801) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 230746) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) +GetStartTime_LockupTranched_Integration_Concrete_Test:test_GetStartTime() (gas: 307627) +GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11809) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 276867) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 64268) +GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15755) +GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 52571) +GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 54618) +GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14524) +GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream() (gas: 303573) +GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 68952) +GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15753) +GetTranches_LockupTranched_Integration_Concrete_Test:test_GetTranches() (gas: 310004) +GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13519) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356065) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304847) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11934) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 359040, ~: 359618) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 306462, ~: 306683) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 275415) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253544) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11920) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 278630, ~: 278520) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 255145, ~: 255380) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 357087) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 330413) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11942) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 360154, ~: 360186) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 332001, ~: 331963) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 483969) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 305109) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 298835) +IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11294) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 384875) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 254006) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 247567) +IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11318) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable() (gas: 533279) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 332234) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 324435) +IsCancelable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 345085) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311529) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299599) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 305439) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 321700) +IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11580) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288614) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258551) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 248354) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 254354) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 254797) +IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11623) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 368598) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 340178) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 325222) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332582) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 333051) +IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11632) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 310963) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 298184) +IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 257950) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 246904) +IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11182) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted() (gas: 339577) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 323772) +IsDepleted_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 298544) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 11602) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 247261) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 11623) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 324107) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 11610) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 298690) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11689) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 483824) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 247432) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11732) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 384755) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 324278) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11719) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 533122) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344575) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 311040) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 299017) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 304957) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 321212) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11118) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 288095) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 258046) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 247756) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 253866) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 254293) +IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 368035) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 339629) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 324580) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 332050) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 332503) +IsWarm_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11126) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 20092) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 19732) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupTranched() (gas: 20496) +MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 911452) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 311027) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304884) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 304855) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311672) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344510) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347729) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 489143) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11121) +RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 49760, ~: 64695) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 258007) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253572) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 253737) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 255135) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 288004) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 291150) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 390054) RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 32677, ~: 32471) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 339091) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331273) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 331424) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 332554) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367389) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 370561) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538043) +RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 33537, ~: 33714) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 339613) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331795) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 331944) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 333077) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367967) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 371149) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538413) RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 5, μ: 41154, ~: 40603) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 673760) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 666877) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 278302) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672112) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 667440) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11618) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87301) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63570) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24775) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 629158) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 526920) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520007) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 227020) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525172) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 520570) +RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 42343, ~: 42478) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 674450) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 667547) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 279340) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672720) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 668110) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87243) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63573) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24758) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 628608) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 527612) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520677) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 228094) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525842) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 521240) Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 80032) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65826) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65848) Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26936) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 482308) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 749480) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 742567) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 306605) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749114) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743130) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 481702) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 750292) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 743357) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 307711) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749898) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743920) Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87098) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74613) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34304) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 703431) -SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 12029) -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: 18460) -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: 546503) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 12399) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6618523) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2304797) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6618805) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2304889) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6628035) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2314332) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11634) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 321307) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311132) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305062) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299139) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 344739) -StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11637) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 253708) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258117) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 253958) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 247865) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288199) -StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11659) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf() (gas: 331933) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 339741) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332163) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 324702) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368102) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11349) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46012) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 50875) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 242637) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20263) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 25627) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 63926) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20393) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26723) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87670) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111421) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 5, μ: 2511998, ~: 2840809) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 5, μ: 3710255, ~: 3160094) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 5, μ: 259274, ~: 259452) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 28307) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 19297) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29169) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66161) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 22311) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 28824) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 80402) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104039) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 5, μ: 240765, ~: 239992) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 5, μ: 29242, ~: 28966) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 5, μ: 246655, ~: 248105) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87148) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74607) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34296) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 702951) +SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 15233) +SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_DecimalsNotImplemented() (gas: 14011) +SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_EOA() (gas: 12384) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol() (gas: 21211) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 65033) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13573) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 549340) +SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 15218) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6621165) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2173601) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6621585) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2173921) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6630809) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2183286) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11639) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 321826) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311658) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305618) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299673) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 345203) +StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11647) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 254225) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258634) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 254497) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 248382) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288693) +StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11669) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf() (gas: 332488) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 340274) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332738) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 325263) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368690) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11363) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46712) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 51600) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 243140) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20956) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 26320) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 64611) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 21041) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 27350) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88316) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 112081) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3527814, ~: 3132657) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3974945, ~: 4117049) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 275320, ~: 269270) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 29033) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 22523) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29895) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66820) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 23037) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 29550) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 81106) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104765) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 250714, ~: 250611) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 30129, ~: 30364) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 255728, ~: 257888) StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 43891) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35099) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 29618) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 34982) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 74969) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 29725) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36258) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87534) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111207) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 5, μ: 2959814, ~: 3379078) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 5, μ: 2997213, ~: 2909950) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13902) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 44651) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35797) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 30316) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 35680) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 75645) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 30423) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36954) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88288) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111949) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 50, μ: 3412261, ~: 3624836) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 50, μ: 3836358, ~: 3850731) +TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13949) 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: 13877) +TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) +TokenURI_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13932) TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) -TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6601) -TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13899) +TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) +TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13954) TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) -TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6601) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 281816) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294142) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 230015) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 242845) -TransferFrom_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 307514) -TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 319688) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11972) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 312812) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 296044) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11985) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 259524) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 244781) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11972) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 339741) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 321583) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72520) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14131) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 250166) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 160470) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97615) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 138955, ~: 157016) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74730) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14116) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196381) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 115324) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99898) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 105715, ~: 113052) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83583) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14138) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277260) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 125432) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108707) -WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 5, μ: 108104, ~: 123265) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 137497) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 77911) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 117056, ~: 123442) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 80372, ~: 80265) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 78765) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80135) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 77716, ~: 77609) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 82596, ~: 82489) -WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax() (gas: 90206) -WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 89003) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 5, μ: 87584, ~: 88106) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 5, μ: 91464, ~: 91357) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73532) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20750) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124808) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83005) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 268527) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6576) -WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 2695106, ~: 2695379) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 75674) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20636) +TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 281658) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294710) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 229833) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 243397) +TransferFrom_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 307376) +TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 320284) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12019) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 315725) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 299008) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12040) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 262452) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 247728) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12027) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 342695) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 324574) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72267) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14095) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 249967) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 161853) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97659) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 138167, ~: 158647) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74526) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14093) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196166) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 116725) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99964) +WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 99953, ~: 114536) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83351) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14115) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277083) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 126986) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108745) +WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 111182, ~: 124791) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 138996) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80630) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 120523, ~: 123572) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83249, ~: 83404) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 80273) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 82915) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 78556, ~: 78693) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 85520, ~: 85689) +WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax() (gas: 91922) +WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 91755) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 88695, ~: 88993) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 94402, ~: 94529) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73486) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20712) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124801) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 82981) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 274573) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6560) +WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 2704176, ~: 2704701) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 75652) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20614) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 109270) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 85147) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 221649) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 227818) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6549) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 1986261, ~: 1986387) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 84532) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20707) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124109) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 94005) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 245406) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6593) -WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 5, μ: 2876750, ~: 2876876) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19879) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 65314) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 354742) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113106) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 83569) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 84520) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 67797) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297401) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 354175) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 107941) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 375539) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 354751) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 322132) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297364) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 296886) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85185) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 127476) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 126442, ~: 100726) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 147886, ~: 147886) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 5, μ: 3809541, ~: 4704372) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 160725, ~: 160792) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 105849, ~: 105849) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19848) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67539) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 273616) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 95396) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 65873) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 66824) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 69934) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 229906) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 273047) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 76596) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 280732) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 273623) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 240955) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 229870) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229392) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 67489) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 109726) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 104108, ~: 104278) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 116531, ~: 116531) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 142788, ~: 142836) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 74502, ~: 74502) -Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19855) -Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 76333) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 355808) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 102748) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73225) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74176) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 77360) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 310741) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355239) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 85301) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 364263) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355815) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323117) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 310705) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310227) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 74841) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 117182) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 5, μ: 115236, ~: 114843) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 5, μ: 125232, ~: 125232) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 5, μ: 150199, ~: 150351) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 5, μ: 3284018, ~: 3684660) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 5, μ: 83209, ~: 83209) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11987) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 346640) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316158) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 305667) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 312216) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 302415) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 308704) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 346784) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 348964) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 5, μ: 317851, ~: 302058) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 5, μ: 290517, ~: 288578) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12010) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 244010) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 253946) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 259188) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 249082) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 255565) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290276) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292308) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277445) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 5, μ: 462713, ~: 461869) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 5, μ: 253983, ~: 253707) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 5, μ: 439185, ~: 440083) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11987) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364161) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 337855) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 332563) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 340800) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 329311) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 335780) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370122) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372269) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 5, μ: 328843, ~: 328727) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 5, μ: 303871, ~: 303913) \ No newline at end of file +WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 1995688, ~: 1995633) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 84497) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20700) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124147) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 93992) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 251699) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6608) +WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 2887130, ~: 2887100) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19851) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 65278) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 355910) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113737) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 84219) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 85125) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 69772) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297883) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355343) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 109286) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 376688) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355941) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323308) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297846) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 297368) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85854) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 129471) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 126142, ~: 103351) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 149197, ~: 149197) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3930319, ~: 3826320) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 162571, ~: 162747) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 107201, ~: 107201) +Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19826) +Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67517) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 274768) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 96056) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 66533) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 67439) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 71955) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 230368) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 274199) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 77955) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 281870) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 274797) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 242127) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 230332) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229854) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 68168) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 111795) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 106092, ~: 106044) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 117877, ~: 117877) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 145053, ~: 144905) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 75848, ~: 75848) +Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19833) +Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 76283) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 357101) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 103451) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73928) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74834) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 79361) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 311290) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 356532) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 86758) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 365577) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 357130) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 324426) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 311254) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310776) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 75563) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 119282) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 117380, ~: 117109) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 126674, ~: 126674) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 152488, ~: 152396) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 50, μ: 3656828, ~: 3369659) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 84673, ~: 84673) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12001) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 347152) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316711) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 306125) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 312711) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 302873) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 309163) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 347262) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 349434) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 321569, ~: 302618) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 285304, ~: 278607) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11965) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 246950) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 254430) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 259672) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 249588) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 256071) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290715) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292814) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277929) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 474838, ~: 475697) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 254609, ~: 254885) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 450939, ~: 451827) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12009) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364842) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 338486) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 333040) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 341300) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 329788) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 336256) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370722) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372857) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 329755, ~: 329375) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 304445, ~: 304467) \ No newline at end of file diff --git a/.solhint.json b/.solhint.json index a40b9ff6b..d9bf4b91a 100644 --- a/.solhint.json +++ b/.solhint.json @@ -9,7 +9,7 @@ "func-name-mixedcase": "off", "func-visibility": ["error", { "ignoreConstructors": true }], "gas-custom-errors": "off", - "max-line-length": ["error", 123], + "max-line-length": ["error", 124], "named-parameters-mapping": "warn", "no-empty-blocks": "off", "not-rely-on-time": "off", diff --git a/bun.lockb b/bun.lockb index 73c05be7aa4f4fbb3ca8cd9803bdb6e630934b2c..2949551727093e8e84bd64b7523c7b85388e625a 100755 GIT binary patch delta 47637 zcmeFa37n4A|Nnn4Zth!TXU3W}lF2^9Fk{V@wJ?-wFc`ZTV=K+56iU&R4$9tQi72v% zqNG%|EQM5xqS8uI|L5zv&W-xk=llKt{{P?O_xL>?-4CyMpZDv$&pGe&KFf8kYwm08 z`J(Xdj|xwVtG1!ad+(k2Zs*;r++UE}lRj2-G``R1V)MW2Dpi|m`;ub*-rM!yz4HKV_4INs)` z_8FF;qC?ONlHbe9_Et8w@;YQ0@+;lo^Ti?;B1_>)&LhtHT;);=-stlcfF7ASEMp|q zeNxHiD};U+K7xD?y|D6Ycy6U5<#y(gXE1hxHwsHFS9T z@HC&VdmWEIhRjE~TafZ;R9#Qc9GN;YD>E%~fO9TXE<2qbsD~Bn`+WJ4F-Tbt8P;b& zDjv6r_ga4usoMGtPE{a$3(++Yvyk#R(dLh3Br?e#TPtCx?8-OrB32lwcG5EYqz+E) zo7QJ=dRDs6SKD_-L$88bw!&{pdJTR^twktM2A;U&Y)+^TRFVO;9-4IN2Vduhoq16txs}F=1IzasfleIsTikc*62TY zSa09pre5zVTK;Erje88bn(dvD+9!=}zR}FHi!}Gj-;Pu?QiqNmk~*@_fLyq#dN0_h z?jYLAcUrjh+>kRUtxuoSK|bG&ExqtOj#PmOR+hE0pyLmhsJ+P+@0VF4ZOq7w)VErB zgEBC4*wB9IgVUnDkM??dW2bGnY?p-;Q>7=`c#UKX_GV-6p>YE>R!!S_z4#fa#quT6 z9jn2E(}#~t?{li1w>Sr-V###4yiFNeYmd&ysEYSqYCdHdbD|>jQ z`wSa4C_T;RI}R_W_FDM{QbTaOrzh8;%lQ|PT88DQy#jJ&FP|?CnT@Q4?1-$1ENk_1 zcldlY(6=DjFS2tUB~b^Wr$^*mZ}s!H`+PUS`>D9B3RLv@u0u9NmP0N;ioZasYIuUp ze=Cm{j(L53zT)t?8+nfQAipa5air{%`Y9aQzMO%XH8T5V4)&EILlxIx<5thgBh|B& zNX2&_rP!QvIt}nD*o`cL{xW=da`GTAzYtQh^u2*TUraWM zNtBL3Zh+9nQUwET{TF0_`~ste2T6JO&#X(8AvW2In{^z zeC%O4X?FG84qpO&Y+B~fY|_5y78%_#?N;c!3C|UYibzGGgq4fAP{^^anVw?3R8Gm&!SF=Sq3DzZ4T zGg2LCiPVr)N2;N+NR`_=(c@1MA(hMCYeTgHSps4nQU%&R>@_eIT|MuIEQaiCWmBXY zDu~o1JI_T}JOoi>#cAl>KmI8Dw{) zmTZ!hRgj8C0i>dO(eZ}wGbDU=&JV14jrXaUUN=%^dH!XM?3bXhy^pT$MX!iEZ2n)b zA<>RRuN~12y@b6SoQG6&pM1uve*=$RvO9y+L^_6)ee{YyoE=o3jI6w}MnmS|%x*EO6 zfoB&vOAA$L6ZgDV>lmcElYrFp>tbukdBMwXgRXAXK+2n&7kjm*W{w@&XHfdcMow(u za@m!v)v(MOLsN&O`D!fntkcG%^-1;ld}q<+>j|V<8=g9HK#f6ZV-HyUU8Gvsf>a+~ ziB6(u`+3U}BohK_MY6e$;2@1E7N zQ&xL3m8DT*c*d~doJfcD9_aJ6hgW0KLe0_Drv%Hp5u^{tnBn3-Uh6qIdRRu^(HW`3 z_gTH4CIp|Z8H=crSwXo>7ssV0_cwy`IX3zhM+z= z8&A%T?Oup&J=wlx5W2h^+~LJ?2U44J*3f=w9PWLuSiN^vzka%#i(XCU!WYAC@mpSO zM`jLA?~P+Wpld$PL~55I5NsWVhP>_Z^9g!6UtM2L$z5IrIT$EP?rNr@-0ygv zj_jM>U#q`&`cQ2!nHP6Cd5f3L{_tJT-`L&W`gp|e=}qai*2`ZHn}0oAMh~4|(Y$ue z;ap^B)%U^s-rUkXAiIRG_y=Bn8{oD3J&$B?vvUlI0uT=(HTq+b?&KYo(LZ&l&(~wG zS5XI~__VYd{n9fsNA^wYoz)svbEld@ZVP4taJbt&Co6hp;?`_09BE!A=1yiBxkx@3%A0p7Os!7k>~*e@f-N zOUD#|T@acXseSsS4Ii25tNF1Lh>6QyO?C`4J4(9T)5INKk@v@W#zf!UR+0GhkL$z`m^ub{_KpoG3S+Vjq7sdsa3yjtp;iJoSSMj zaH`g?`O3^%xk^V`PziPV$~on0S9dzq3j1$$4!2JZT&m=h?2r^VUD@f0c&mytyF*gM ze?9lV6bL%03GtB{Xq{YbLGAd+c(g`nerG|8_{e&+nrOM4^7Z2*r_t1q-z!(uyA#Ug zEFkZ8G?fcGCtAh_=2vxQcS?%vgG_P@ly4I6FXY5_PWE?ndhqixXIAIr$nI)9Jt5!c zq}Go2H+EvXBnLL%;PmX06e(EU=W9z=&{@zn-rv(X+$A}(3{Kv7ZG2SS>3M5Xq#QkI z3>k2px&y7YTO*yJmDt;o1E1dL^t>&}U)q^*Km4v zP4ahfW_3*tJRRp8=}H&ke7=TM=vM^%C7d4Jk|XVI^7)#$jhv_#?|;NO+$}kLbb6*FMVi)%dMA_dXe#b^ zPBcvjqa>iv&t~zFlW1OPxmC`Y)gw95hmNc5+>YEbPHfNQz@ges&z?zowBVWO*UjfBDd;=zmjq(5HS%vP0Y2uX0XcQ*l`64%eMf0Ww zy$mPS^PIk1EHV^EW8(HSGT&-Usk-rzy=XUkc??I*`aHoy^YSv#!2Jp9)c2T1YiSI-+R}Gghp=d(hNY z$kBkTv6igN#Q1O?R)^{|drk!0(T;S7QCa3R)(@Z&Tg8et-$zp`Uaazyl$P7gYe!PO z^(-GiQ#po}R<>J9uaytpj)arFX1$8KpxFVb8}Gm0>CrDavKr3o!ioI}{$%G!za)Of z_D_zCW+c6^o}hE<(9}7)+ASfBqRGbI)i)u`$jJrT=o}vzg+|Y@Qz&0XlOd%DULK~E zwiEK`WM?#Wi*U7#k35dX6sAhnQe-!pYRThqGMGo)3N(iH9P59hy7GdvE zP`v?Zho;cE;R#Pblgr+6nzl6(wgfR@wOz7BudL~MZM@=K3dkRXrip)fLkY}jmYIe0Ga-BqJ#l+a7nFIf;ppj-<50861Y{ezY!V zM5umzs1}v5zqL+`j3A{-yot5UYRq(6JBj9vo~}$4oWmoNBi%bjr|5}~6T((;7e;75 zT9R`#BQa8jRj43)%kFkGRfC^Hn1fgH*gAHjsri6&;*NxHXK(4?OM?U_c64%N5RB%7 zTT$pOX-=8WiJ@!gN+YErtw?Efi3oeecr@*C%%A4*k=M}JSiC(eaG{HHWK2?|&aGY` zD9|<`jKao7X)UDR(b!H^7Z;v-w|S-Aw*AAM*m22`C2*=A``h9}U!gU0jy6h+RO;%@ zIOZ6!z5~r$7Q{L{8%-WwnNlBE>!71WAMO^NB}6%tf|lg;dZ&@o0 zhca6d!YG>VbhBl=|6!-c_~gLr-JRLvlOh+$l7}I;M-5ZF{;`jZi;rYp(YnV6E~PlL z?@Nl*?BTiRbISLRkMu*+?&0kM8_+am*%Wc~XEco?mUQw4W~G8l)!n%S{7IXS#+GOE zzPVZp)wrD?JH75}6eiK&ve6tg{!zI`;#e=AFY~h2`A(i}UeC>N{oXB}U#Q#kBIugc2y8zQ0p) zQc~nBG;Z0xWDM{sX6K`sPtaKJy4_g1>6Dq07@AG0xtlsls*RhfGB}zVMyjdHtt8dXOTa-e^Pb7WdlWNU`c$ATlP{IvMU0H(9Ti^l%@Dq3A#*&@G?YUc7fi8dH{^)-N- zn@BcHLpPsc39KLK%zh#%uza+0pO4+twl?sxrVHIx zH1)>~WF%jX=QrBj3>=!*YU=QWFpAeq>ULL2@k-qtA8I{;-Z*o5F#Sp0>|UlmA(f!0 zL}Kob)*|0~qt&ORceI{~#+5|`Zz8=aP|SG zViLq8yXTiWw?tzG!3np8|GuKfkIaH zq3E@>Cn?V{?K~^cya4LznCs!_Q0kPQg2t7Z^Tacx6iVFh93MV~rXjXxnr@Nsr0AF{ z?vJ9$NB0C1+K+ap>wE3V(b*=eDQMnm)b8`$WT)i9q)5jp-pRl{Z$%t5jSE{W1@@qE zn9^cq`IdgfYvdY-i5%*Smh2q8w^5jciV#dj`3#y?4f`Dxlz!CPOTs!6hWem!*r=Bn zo<}MfD|>i+BNB#)bBpP^UvsKAtZsKA{m`_`7#OzKxoFy8TrK*mWh!KN?}Vd7}1}ea7r#q@;7yQ zEK3fIa-7-A*x?-K$g-r+XHPN_oTJMULy0q@DTfqW4cup>?sQX4pJHyhDRVh>meg%t zuF=v|35OIL1F7Sr+}!+iW_khj@rmIUs=706b;Li@IkF-t)O(h$IAw+;Mm{2?KD)OG zk!xmq!$k+C#E06U)p3rFNsQb_N+ER5_>m20UCZf&VMI;R2bw@++0h+31 z2$)2Lmv}BRs~M1+(HgjUsZ6PCv|4DminbC>6Nxp?=I|9-eKdEvMH(&j9AGQu=y*R` zZ7+|fCB9|eAYFDm(g8-D_R2nnChwS_3Gv}KZQd2@+%J0VGD+B&o1n>iCh!9ZVHCy0 z+p}LoySzXH7hiN{Z%c|aUhajI!#fwjXVGfw)D`|vDT>;57Dn={@Va1$uOndywdAe$ zIaXskTgvqLk9(lKPX6;ChWUaa!8%F3QG|fn^dOhRAXVK)xl}J{6+3O;8rX_?? zl5?lByXqiOJ%zi4lvX9Q zP7K$1)obfY*Zae$1uwYIp?OnI`{+?L^_V^|v18YImJD=4e4zVUr{udy0khWWi8!~` znf-23_{Mc!@yjbe(icW+gNGP{;sbNnIX!ptI2}^HQt$BiNRjo?-6!?=gfNP?S<}V* z)6rUE=;Kq2(7C_Vh#ZEk56gCVIw8ElGhxZJjt_N5yG4hs!0`>v?0rdrk2X3zyCsEU zHb-x_6#hM`>&VSOAN$rcV>T>6u4!(bL7LM$OqfKF=k}A^j^Co+DQ31@qwm0oY@DHLZ3i-3!>zk zmrp)4&<{LB~jHWp&yhD7r^jn_wmHaL+HRZn2!$}d} z&giUW`b27@>0rPNWKj=6^Jb?Cys^`neIzLo^Y-O?eV)vZN7MXaa&Q^lVe?o_5c>DHoG;hW)U|=fmW~0zSKajTDnSCrNFn_mmcI_9sb^BkxB8wtzWP;RC1S ziKK9k54@e}@<4=U!Em3%)0wlRI#G+eYlR!{@dn7VoVFnnhUnn-L%Z}IH1(fttW|uV zz+R{1#-vD}z0oEWhIwc*Vf@&!j-q+t(|%HHpL681q;RW!-cjeu29*h8w_Uc*m(bKE zYo7}9@At;n+w{7kdDW|b&VHxo$)rf%1Kzynve-60@+6u}+*4j)?*XUe7yMrALyu%F z5v(pBI@QwQA#5BniC z#@@c;{*2|a!Q^~iY$TjI?V+u@XH}*_UWWht;1S*93&%yNVRaA zJdr_6&@`XCE}lfw(DT@(c0%|_)Nh&!4MS_Kd;iEK}RGB@{dd z8jGgM&yu{CyB@S=p2lhKS2WJi4H5$lKX#6sNs5g6*z+Qf4&9*_(P}$KdHQyYR6~k! zlx7Xa9Q8s+!~2++N1c-2Bt`ClZ0CBzk_){l6K4)Z%N&b#Of%%xV@}C$lR^_Ao4L=2 z-Xf*Qv4T0F{y}!TQv6qzmsIgHR=-+C;C`~aq{{tl_5UP8*j&_XQ-R+=ZV-@SrIJB@ zsNs<1C6&x=Wgg4B($pwGf5`QPp>rYg*=$KA^IKg~?H9KC|3u2P2tVXbFU)S3ICmF;p9y`f~)?QM{M5`zI$@M!m&X+KK3;GKdlCw>0o-57N zg8mZeVw&?qvW1l`rSSPXsjQoAzGN7^gViOK>}d6?rQcjC=r8B|c0TO)o5qFg=yb(W zj&-*su9l)wEHA0f-frccmX}oWE~{THMcr-rtEKAcqtVfagj+#hE7Op2sJ|^JspJ4F z-FTr(%5D%+qn2UwGm-j8DnHBeqbx5e`|*CSeG)Pk;q@>Fse<=g{%TnOe!Ar))srW! zE~$Au3#sx?TR8_QyZJ~htLKrjTc*{nj1@=~SZVcFko@zlwsH+p1vesPw^^Bgk)mGX zhvXJ3w<0zFw0PQORH$o`(HEqV#Qo&4sSA`9%Y-sHy z)x#D@HQdJXl4`i4E}J)e`>|V6Ir1a%TRrre4 zS6jITsgI=WUbVVp9PRr)Cn3*ITZ6Bxfust2ZS%jgyrlSZR+m)ypOJFlH=BRS%HNT4 z+}+)g0V!7I(x#RhLKR$tRK@wM%x~qjNb2wvw0a?=K9Xv%gymzbUKXkPDkAykt72s} zD{mCZM>2RfiJM4h^3|~h^^s~Y!Saoe`bf&IiIpuZFDbsY)g{%DHj-v@2`(L~u05(O zI`Kp1w<#Oh)$%Epzr*Tx+5Ee$-p9&*R;F7y7^yWf5~+4ZAr+T&VRX&dX|h62xAF;V_jgiu4*7CthP9Iv|CH4wm7K*7**zV! zS2z;xM^YJctej{0tEE=R^EQ96&Hp>8hL_ma>_orL2@g`O#HD0n7iLlwCoa|Id;^P}@Z?l!v8}Dp#Qy*y}XqbkjkpU57k>u%0EceTiuPn61G4bQWf503;wT2Rb0!~QyZy{CEEHVRevL^ zXGar%CuP_eLsgh;3pPQjXU(nN0;!Lr>|0v>?__@RyV!h5?6ZBhT0&9{b@eiQ-7J5# zR0G{Df3*~!0x!pIxA|8~<=+9X`tL+azst4j9!+>sSNC*lFwn|DNEIAn^`TY{L+W$2 zRK>%^n;Iei^*TfPGEuc2$5`|KB<24-)=pCTeO6Ae{MAx!JpeDary|QDmm$^ON?q=B zB;Eoc!)-{7zTRcdJY4p~V2C%4etB#6T+tA@z|| zayUQKa0XHZGLdp<6jBwBL+W$2RK)IwSGfmmzNE@Mj1={#r)T>fC!va`A$9dKNEMug z)aQRis_0x>UQ+eXv$~}8`L53FQ$oZ7WYEmHj>~>I)a`EmpQZeI)AEuEz%Hcb>_N-_ zf01(IP>4mLhK|?@|0hy`J7MkrPO9Qh$=Blf#@b1$o$stJDZ6vgMRCq%NGjudt4kI{ z53uCaa70VbO4;SLx}@}LtjuTmtED1X5MGWHw)urcXs#5qM6tEC^7bzg(C?6K84fMH+>|vj{bcL_wQ4oo=K4 zeF~>2@X=E_9h?3yehO!LRPevsWY@lrPk;L6@DX1QoEH1jP3xDwHDGqksnfnzx76*N ztNXqk8P#6CKHtP!Ppvy&rPD7@r#*G^T^rB-)FS7?yw!DDb?LVM$%1RsD*9(uX)?Le zspB6#bo0o!pNVU6^XYz%)!lzM*XNlPj%{kPY2&i}RZhP;enrNEll$K==++j$k1JL7 z)QcOd_o?{8&A-g(l)8WU#C{9cHg4;mbi2uV-rvrjZMHq{?`{S>@6T^4zW_18jCcVe z<^_lYA|5d17enk6F>x`(M6*Z4n8gtFmOwmgCMkbQiww$W-Ntx#GDW@ zX(>d@We`)%^konU%OHLd@wjRFBE%^X&%FpS-JBCK^F@fR%OM=IU^ztVSZY{(rb56v} zwGds`LA+uXtb=I14kEN3VvXs%9^$-+H6qp;{|1P~>mkxMK&&^bM5JthD7Fz|qeK2HTBHlK&wn7{dF=H#lJLZIlNn0UWZiCourf-8t*aq>Fi1$s? z*C9@cco*`m+aV5^&f6i*i&!J#pz-g3SiBt~Z3o0* zvr0tD4v1oJLVRRW--HOi39&=OQB&wGh;<^e-hw!8wuu<<7DVNp5GTxtoe(iQAr6T6 z%#?o{VyB3SZ$q3kdqj+R8=~GWh%e2AT@Y1wL7WtE+SGan;*f|L??8NQPC)q2m23Rm=#>vUF$++*G?+b_A= zrUE^teCy9wu6EtECh^(Un?6e}@NrB^|3;HHExDzC{HGW0xN+g22eqX*kJpd!ET_X59D=g(%z`?T_l@qd8Vi{HoVv=8w5f>|XZbK7?p_5F)>seh?zzAgP~3 z6fjK>L7Wot+#!fU=A4L`hakEhhA3hd9ENCp7$S58qL}G?1me7iH6ltF|3?suk3gh- z1QBaiiAebfqS(g}rA+F_5aEv@c8Dlr3LS-5CnD=8L^-of#DJp^m5)J`HzSTg#2kY- zAflove;i_`h>6D`Dw{nb#vF&J_X))HX2K^BRX>3^DWaOGbpqm$h#4m!s+$ucCY^w2 z`6)yVGyPMDgij%U5^X#7VFClh_Xlx3df>l8$?*(PGZ zDTvCaA)1;Iry*iaLmUv%+?4+cVyB3SUqQ4qdqj-+3ZmZE5UtFFuOX^_4RKOL8&m5H z#32zg&Oo#?Cqzs-1JUvqKPz0CAVuCSt%35S4#~NHrsVgoybO;(&-gruc zQ@;4FN9%`QdFRCrzdbQz;rTw9MduvYuqW%lH&q_*9dlowxR=*I+VOZAuiRYTe6mdE zi&T4_YR#I9v@_Zq_6LaSMTo|MKs*0f)8jWRQhtNj{2Lbcn8+oF@Fj>LmmtQQ^&-}Z zDDyi+wn_gTV!-bZyG2Yev423s`~flk4~PfM+ah*C%&0*l6K9MKbe}OMkblNew1-VK z`B2p#$Zw|lAtsy20f<8)&dRArOoJfAqyWU6AjDL2T0}w+qJ1ui$IYx<5T`_35;5Jh z2|>)v1+hE?;g|~|T8AKd<%XDHmgI&wFCu>)2xEHWfmoayVzY=@CK857$pbMY4DqyC zFCrXqP7pG0(*2g%}Wl7@rqnfq7d*OkRi@*FY>XW3PeODdMPz=S;PH z5M!Y`LJl5AB!bsa(;+IBF>6fW*S@zF)2U9oNFPLo6{l^u7zk{ z0OBPxs{q6)5tl@)GHnV%%q#%0ydcCY=7NaU1tEGBf>>jg6oNP}B7b3swWdd5h{c5< zHj7wqB1Irl3PTJj0=Vh{t0LX0m4vCX_KBBmHb zjp7h*n6bqnc8WMEVuz_#0%A;Yh^ZwY-ZFOjg%q$79ycEPfb3sJwQV_jLLmV(mN<*9% zk-rSYLDQoQ#NyHrn?)Qpk+KjeWgv!>h4{#<7ZENCQKlTkQIlQ{Vx5THB95Eb>mUY{ zgBX7u#0m4Zh?wgjYLtig%#1A$u~WoR5hqQx3J_z;Lrkpz@ufK|qG|<*#uXt>o5>X+ z4v9D`;%n2O62zp65OXR)oHeIKBvgWEUm4W96cV5r5{K+i29^!lzEb>>y;uq7SD#YUJAvTM+U?SBZQmR4>sRnV;tQQfk22tjQ zK)b-DfEjp0pqp7IX1AC>0;Xhjm;pDyjIT~1|Jt{!2L?q#4J+_het8M7gy~c-u$9$W zsD9wB(A?^L>&0}g6qiAzA$g^B24a zW}bx0r%K+DY5qkUygz=s9$7_IY;+sUJM4AukNZx3eeGj+1$qbaU)<$>`77t^caSp7 z;~K6F_X+&aVQr_hz#YN=lRvu$^KQMMe)1}9E_2UsfhK9c|KWYa%_d7n;plNVs;k5l z8Sr`9+UVCZvs}jKd&YA5qRkx3&4H7yM-#E8{G~vV><6XuS!m7m4T>q2TLh;n^|h`w zO7MB!a{A)tI?FAwoW6fH#&XebF=NW7FlkUwbR!IpR?S{)=pnadfsySy1&Zm%Wf}NPG9j?!-c_O%dK@ez6MwXVu>Z! zSwnr7aH-|iTdo-TiEjra$a)0f;Xir|yI z$CB5f=u3?H?6q8Z(lsr&&vF&u%2{r|LOz=o@dE$$I63fBGL=d|%rctk*p>X?QopcgAvO;8f2|;9JY-wGTC16MSd6 zpKMuPANIXxIlUI5`f7ttq_r}BiN1AH2c;3DKEGPSx}?ik?xN-D!5vpEe4_7{)F=Ik z<)ZJJ#KWDioZdT8k{4xtpIPn?%Vjr!%mSLVnnlXzU0wYRL6?iZtdfZSx-G01SCni7 z-mqNIa*g2z!fAHrf|LJA;18h5o!ifyt58^6#2Pjw{SDA8&TF}5 zq@PgDe4;PQG$$SX)@}4x_ATJlxr!kA5=~3e>YTW1^`e71a5K;sSv468*hX5B{v1w| zG5W?$Ytpkc*nITXjmowGFJh<3SlDuHNw0#_r-^vt#9UPCdXi>dO8C2PBXcTEz7(5ZtukD^&dId8R#43n%w0q*M;=maBAOo zoh5H2-Ou)}yyb3#>uUW8II6^sR1Ep;u|o3!3J)u*22`jBn{myE1$xxS=-1^UEWE{*gs z5sH6;CHs-qMAWB&<@%G>`qrnRTFY zfFwBgHGsh=`m(WRZL&2SLR#N&)~sz}xuK-BN;DapT28%Cg_?}bEH|9=2*yT}thwbz zkk;D^nooL7Ob%wK|C+&?P%SN)Nm}dEon)39iLQ4h+(~9RmAeg26Ds<9SP;D7Z*Wa(9s%>BaN57G|&l7^XDFLGf~i|i?zF#bTiA{ zYPs=ndQU?=zs+*@kybmZv#U6bzo0ij)XQ$xFo$$0dBvx@kS?YzI5Q zo8T?*HrNH;0q=tMOnTm6t3p3A0Kb6q-~#y7tjZfKmpuUw^hW}8=F=HZFT9iiI@?_b z^g>K5C<%0q%MWyR>w(@A=qRS6*WEzJtv;YH&@rnY=npyoy;3w5i~}P<78s@1e@2ry zO}OnOQe*{WMQ{h{&Y%mp73f%27sP{VKu5BhfZi$p-ETVN z3s%V1k?a$oBiE-u$E?r6N$>?I0*Zp8K(EE`2OomNK%3S($aleR@E&*{d;s=BObKd5{Wv1HYdQS$}1r2hd+(C=SYi3ZNpW461@Kh=9D{8lXS7afZgf1>b>l z;0N%PX_-G5pFNO1e#0RB49#4w;&rS#sEUVFP2j0bmvRL~pr z0ck*IC!LjAgEpWoxCOKaItO(IdTFvIIM0;40Dc9(flJ^I;3Llu0@?fsf)L0J@`CR% z_zAoZ_5huGbj~>dJ_I^~&O*)xcQCrWfZkHpEy@qzN1$7iYH&Az>Ol9#x);{1uWoB~ z8@maV*~*V?K)0OR!4B{y*a_Y?=>>vyLb|a#WEK<%*3`~>66i3M2}XkZ!2{qyFcCZi zCV|P|5%3sz983ePsHp+apEuCq>lEk)x`0lgBS-`Nzzv`}xDgZr`nxcZ^ECb|_{nrF z7;KlVvrrR|1QNmX*enK1z*6umoL=<$790YH!Cqj1-gL_XdNVGLs22dkfnKIe0Xkva z01ARaK&OkJiR3RpuOXiba*XqnNCmov-U)Qk)!C{X2!aq8jU!{hJ>XuTzt^!2=zsE%X#fSv^u0x95j za3^R7ZUG&^12n8V;0~Y}Xb$Rws^A7t7L)@qposo3MjVMk;7hzb1a#uj31=(mbf6o~ zKhTRIOMqBV5^#g*yAG5Gl|U76JvfW)H{g448tAU-5*@3Lb9F%#5N)GqHhWtkpp)-C z;9f8uOaQt+{0e*rmIB=et^*suZ14=wZQEcFtx&gOErIT!bjPH-A>I7^u3Uqq^R!*0K8|@G&?F zj)BAAAV>uID?2{|9bWYpe46QqtYf*3%(}a62xifPRyfsMj-kszK|PT!hX&GE)IpuD zyMj6(7W~x#&7G*zt*N60&}mt9-C2!9X`oO>E7S>DnM0A+6~=8o58j~DaRn)BA1)Rw z7HFzHK+{vFJs;^Y$dN!_ZTJf4=I%67o81YZ(}Ax3I%dXz*Vmpb5xhN|t(!D$mWzNk zQf;W(SaZMxpp91CHn0^qK=xaJ{hPna z<;2544#>F&H38JatG$vl(H<#JhPsqI0o2PV7wwU3WfLtU{z;%HJp4>$l0f)9bNPDemHY;?B% znDj^B7|`!@K0zJ_UxF{dNuVp)=g7~%r@;R5=MUxm2uzbo!P41hNPTT{_2gH-bV*0o z=Azq5Z7!pMHkc9MubazoxWOO-ex}@eK%2~c$SKG%$S`?%KyDBMzrY2MK1~8YiQgbD zf(zg+`18nLLBLA!KJ0!+{sArlr7MCcue7+CP`PZKLF6DHr+XpW0A1>IDkuo@>J%`U z%mOGyk=G)x0r^2bP!H%Ptq#y>p*E-mYJlpXG$;j1f>=-j6bHpXQJ`Z?5oBSYlZNzY zTRMhR)PwpeKzDzYMSw~`7vrTEmq+T%avg}CU&JX-wn8)=J?C6+dEHft8;tFZ$eKW% zkdwO8Yz4C8`H=v0U`hr_pfS+xX+sd5fjUJef+nCTxS2`?aV1=$^R z1-Ahm=5*_;Tj0*1eSqD89ZAPCmc1y@jr0=alb{Fbo=LREt|mH%sXszz0)sEUj; zsa1m|(q$HHG1{8UqBY+~`dZB8ty-3pcVRFBT-_V-(K@1DM(Y`8PE-wEA1hjv8x`c` zpqTR2g5}Cw-N$H2_32@XJ!E=S3-UK;QKy)Kh36W9XVQParic)1@P) zAuAv?ME9BUHv~&$tEfgtBl#rItk3~UvtTCrQ((kZydgag%mL4U*nWvG_oq8_m zMPNSA)Lw{OU?J{Vk1y$xa=`5lq!yBVectSme~Y0s>okjgAiV~h17Csfz$x;+L8|-j zgLi@YumiaXYy>O7GO!f9iv5eonHMU@Dk3w zg^WH>*hRW44ZVll4b5O4O7QK(ly>Dp@!9v zD%SX&ApHqY1<^`f=S-m*!6FURxvT45MltQEGLg?Okd}Xok@D*-_!fL`devaYO(Lo7 zNL!IM1Z_FmZnRfu@6a;52=^oS62s}H_zl9tzNq` zDd4}eW?a3vx;1^1Os!$TSpR(UWn!=n-(I`v@nCGJqnH=R{Lbgjo`0Zc*&ki=+SKa% z!E|gCEEcL8SId{nq&Esq;2V!$OO!A}8dFb2vr*zEbD(kXY5x>6A}JUfc&37RG$|Mp zc)5btX)@IwujKyGtDL@XJ#+7znbo=m{PDJ$a^zH? zfp_!H?R@QvPcL%&Q!9=q*GIZf;ITG7&V z8K3I-KB;7KH4m25D;kaEv2CyQh+-((FaI>eN3!8{mmx=K83CQHmPn_JL>c~#7z7Qx#7T;`gV z!PwHTP>Fi{=AktFN+E zO|P4S{r&aL4vA)_Mk_kGE6%iT73>%I^(M2jRq#E@oYuix{PAXY>tOr9d$mpJHpJi- z)3FWybvNm4f^~`>tK&_d3;8RoDb{5EcLD$2I%Z{?U_<`^^T!)RaFi+6HW*v)pJ!1_ zeb4{!0f!1KQmaEf}Nc2qX&OkJ#C2Fdv~M!gB%TY zzeh@Ry~*6vjvNMBQ=+~p)s0w&O}%b}$4xVhf6DPb?&UDYeG|=uJ6HujV4xlQV8a`3yzkwlnQQ`MQ$-G%z*gFF7`TS@7L-Mm0;Y_O$8>WGau5GcFM*#*DpMQB=>@^>;*4s*HD zMBG+5@u$0PdEy-mYsS^)AJ@-ecM?%|4~#Y4Y6Xj#wRZ-~mHzt@wHSnGNMB4b`R-za zT$kc?`_}o%X%C$!b2Q+u7gxt!hHs>pCRhaarkEG+MjlTwBky7ro=Gt|o7p*6_Ao!+ zg|zwRj=O^;|3h`hdzzK0f3EJ$yMwj=Ly4;^j+Y8MZ(IKPm7I=dHGLMK^!uJttYP2XV2=waAqMGv>OfM;S4ynitX%QL=;Vr*;qYXEl-FwbybVx79&13O56UwPEn9_#=9vh1Ey znwoh7nTdPSy-nrq4&e%0cNL7evP~Z$M_0rbcCBg^+J5PEce|;@rOfy2KvQrCj(Im} zfeiyqlfeYzy@BTUm)J|b7|1hJ3OgM9Z5agUNcpyuXw>t*50H4B-(kE}i_n?6JrT z`<}Vt(x0mj{7*dmYrp?eCds4@z0w`)WZ=`GX64ZT60>L*Y$X2dOf>U$ldXGUYm;IA zP|&8D<13h=|J*Sf&S)inj`e>Y!GDN?*D+qZoww}2^v`-{=8p(I^A88L=&+mDGJmn^jrpH=9BeaHngg z88?#4(pQ;g#YhTyxqplCQ?V4`J-ua^eEG5e6UzKEOIET#lQ4G%F;Ie-P_Qq{3^LrL`*dCrAWuAF}>Q;?1jmBX48kWVWt77)e)qXg0oetj| z#<;qK<7-SG=p6B;5oMwjasSKrH@#%)=?O%CB{EYU^e_Vm6PV zljTSA%Nz`1s(e}g*tFTvV$Eqjm3+;7?!|r!n1D_K9Xx{BijaE+%wuV z!J^(&Eab&^`AQ5Nu=m&YS1g_(rw}JjQI6RLgSJT*PUSh<4~ zTWSY`ou6W7UTVCc=$fuoZ85rKXJ>S>x?@{B7e@xSWS!D~J9Ij?`TjibqSHNKXHUH^ z$9jA3cWWn2n-xBp;5O;*_pQgdzcI@>PG2HY87#DFgIz~Y`QoY4y7ks%p(Eb>jVbk; ztz-VIy!FeifAm{xLG;|_i-#C=Z>ZdxMw`^#kLSM~$6{q+{-G=Q<8C7D?Yb=e&kM%J zCh*K?v*|u!^rtCfityWOg-g2yy~~U@ zQ3F@Ht%+?r`X8e!JKKw5TG5`brqhEglf4to@HgFM;$G2gH|*Li_0K!1>r>I(?gnth z(?1utA@wek?ybB#4#mo8_5X7K8k)@$IR>_U*xT<*-#lT|sY8KscHr^<9~RS}mr(TL z9HLfuVZHG!`wHyK`5HX-Qw`#6J6}R z>z}=>71JZ9D^=LM&67>eWUf)WC!2dGAx}&;Pfg+((_eW1b*9#2{H|}>Axbx$;zjA2 zQT?+I9RIyKQL4|A2cl%l)nD|8xAV0=vwG1TU%kKrs>|M#z`e=l$=dXG1r?fUG}S?~1h<5tD9LvD-6 z(PewtBMTn7KmRX%?J$yKpM-MmT04d3q|+WV4Ikms|LJ3<<}*D0|88Eeh?(_BFwuKb zR5TAQb6$Vkd?%|F(@dpDgSV9aahi9$dG>~5k7Tu}rel$PRIzrtdGt}1;_m6*C2#rW zyUvbpIq$hEk7g#CEswG?c<^xK(cle%BhyXpsXU4P(-U?6Dwk{YnPa9+<%)dK@z(8< z1~Z0tiT!?FE}rAmiHm2I7I@OTnjijZlBxK_;@wwrs+glwiBS>;ddS~3-|2~IJ;t@V zV$j{@lqosy^s!(vs-oGbzw>{_GQFbq)-mk;zyo!Okcw^N~NA@4zTTrp) z*JsSNfBZ$6nZ71i$~^UWa9rN^DXr7av6-giG{*SUOw(Z+bF74UdRnl3{d%*!evG|) zL)+F#eY??m18T?1rsQaj9V~vs)CK3Oy+V%KC8y&oQ+7Jfa#FC+?>0IuufC_r7k=+t zT}M~wd9%!5ECMghGV`Ys$Eo}}shGNOaO-~Gpc>=cKDy6Vci1|>CBR;&RR0N>v|E3BhS!{0tD zqq7c&c;VA)a=pYg`# z$GEEbe_Pb|H^QQwfDlhLA33a|C!aAtJHZ@ooku^(uQ@u*HE%x2?!^=OxEX|XHt!Va z5H+`cpN^}x_aEsF5fAkE^)WdbymQ}G-mHxtFs3N@m6kZpCVt&t?Sc z)NeH3Th9fzFMt1yOXd=fL-lJa?Awr|HXfhVYQXoUmfl1TS5$?k%Y1XoQ!Jyquuxm` z>rG$2`u%+To{h-3&uNFuH#tu+QO03W1dCFyWl`%FZB`#j$S40ZhT<94Fb$uLn?&Nl_rtnS7Y#7_$5>y=GM+j!nfhr1h+4FC3SCX3P$F(>Js#M&sx-LelYQ5nBznbUNPa}|Fo|3vfd)VN z2ZcpqMs7V-*ak3>9GB*Rg{6px+-2ay>1mkcF@;6@w8%JJXCS20FygOZ<1p6PJc z-vT8a01oGwN3QQV92UVqeG!M#0~)10jUnFyT+9+2s{-~6?DO9jIBm%sacj5_%zZV! z@L0g%bY01*KvKrRkM+yr&N;GZor}x*{aD^|-EYVv4!1Bl5Mcu0)~11mEAQrisAJHg z#0({oUZ<+cVrHM$m3&N5sA|y}LX>4spzC1J_oNoa_goUR!P|XAkWK#Ib%OfSM`xhJ z!nNGlF7gTAJ==J0HD|z-(DR4-%=Of-*!a+-e{D})RT~OKRf}CjlbPO#hVd`JqX6o>hj|WmiWDAARepFSm z--Z{GK`ia!q^;j)R)jtJxak#8S<4e&i0zMmGXu=f|~v`2Qa3Ls!FYJ zD4MrouQXQi{YiK0_GKQp}nXZxD_BwE3 za!=n?#azEbhuh=D67VjYp?zB&`z^I1f$m)o>U;3=F8d=x|L+-nX-c)nvL&laz;Zjy zTq$n=tJN(__+P9Zq_`Sqp zk`82bC}H8*tYQ61TU=aUpoArUVe;bhURiK!INP1if;$N-Ij%-)i6s5a-uzvzZE7$wZntaclo zl6rqDGG)Xl%n82?xkf?xh)LtY!Q6%YBQL*hGyGZN8UT3~E$3XLynF-=mEhGrj_&rG88ka=nn-59#mCa52u;FvCD;l3#IrTvgTLO0dOFmPQM};TZzXt zz0T}VP8{6V)ztSgAKc-WAy{*RA1Q)8dIU|}b7BDtcE$10!-NS1r?L(ltfLLnr`~Fq z^WrQ!`yne7`|i&-sOU13e0GC=gDge28VV?e?0z-0v=HwH)zDEqr93!=O%2^;uT@pl zy9D;>jNh%LCa$|9_acW9OEESc zuC$q?lDsI)l+E>gWp8_0>%230oi}TWXTLnEr??-`iT0w+BuRd}Q|5G_1hW~IOe_)n zq!yL)u#VWgC`+B3v%+iQ5GK^Y)($q8)SyMB!YXCwn05yXvF#o7KD$LtrQ#OBqFQ-t zmM>sC?8(T-O)Uf0|9xZJMKC5u4U+Sa0t0DxM^LT7x%gQFX*ICDVI$qwz%WLQq%0TQ zxG%H+MW7sx7^fQbLS*RVHntPfZ;O+ zO%zlCPLn43rUI=>G<{wHyLT*<_DtDexVU~?A=vi{EfX+z@PmhP8g*6JxU&^!0(Jrm zb{bouzq#+5jT=S>tzF@(7wqlm*T1xJv9mRwf5);0rZ_*B)2=UcKD1aWck1aJ8=E}ScC}QV*09NV>I{pr&7j%YJ-{l|bjM}?ov~lz1v^X7 z-hwlw>0`8EpczJ%RP`u2Wyy$wbD&u~TJhj^;kK3EX|8}~{>RJDYf-P@jKT`ggF)|% z7+-h4&^Vcr7gO$QCq{e4e3SL9RT=~AOLY8{OzlG(V>c(jX&DH{P zYt=ujGVmQr*W(SWXx}sg6RQ8#z=Q6$0M-ks6#CNO)dnA^8$%8J^(o)nz)+pL-{1p7 ODj11>J&qVChW-z-=OxSl delta 48396 zcmeFad4P^p8^`}F^DqyQeHXH1XKXVJGxmKgdx^m?V>e?NiW!x%ByrOrNh*a>$zF)0 zNGg?(B$cwHD1^4(=X>AhLA~DPxBt`g_H~`>d#-cNbJm(%CVnlQr6@?}FWfc{$rpDzb;VCtYj%J~63H+oXqVAt>)o1ZjbWSWY8 zf}V%`x2#-i<+D~kge*z^%*sArQDnG^&sW^%3uOJ|Y>FzCG`_0OcQf>u^pR;}sIFCc zpD!uy!zMfq2nyY*Dg8k#&{K+;g3&uQTe&qbsPoUn4LmE#?Mbm3ZM%X`HKrB_SN7?YM% zy|p*!L()f%7?e6JInw(`ud5_DZKH3wJxnoG+PbaRNZK$j8vBo^K16f19A3Tc)6R>- zj!1W|h7C&{H70dHr}p0BXo%F5)Nb#*7JW<6^MnqOn)Pr;&x`w!>fA)I?7Ox1zW?2#U3U>9}>y1>y-{0XGhAn>?T@{?BpxjR$F?wujT5?*y zSm)jFEp66z_liZ9{0rzZTZ)t)N4@s0ZV5>PhgX}JI?A^VUe#KEvX(nBISOaq(aQ^@ z!o9uH14fPe)1; zdR92atFQt2Y|dF5(A8j_R4@37!k0l0BGq7%Azoa>AvG`OFwTd3Zm5@^fmD>%MHa~< zF`d#ykYymWvCKjiMfQ^cvIA049zDVrjCjsE>VaWJz=lX*Mg*!z=$Yq=x=8992Di z(N+FUWD(@5OcHY7Nu)-A{XQ*uaB{{hbQMTVPfANmn&2CcUI=~J{T}ao!0Xu%c#TjO zq#S95)Fx2O+UG#3BY!X=n!<08YUcn_4HBvoHPaQFmQ1FdNO=m&+d{<_8_56rrB;vCUktl@WgGfdH zIHW4N>tS!GA_uF-;pIraS)QZgW;myESGe^ssyhAwQXSlBv)jz}_(ijwS~piO_UfbF z#O5Ysb6_@jjwe^maVFkeJu|WeKRDMLmQhGKHE`sZpXja=6mTvuN!$E_xu|>W>B1l zZ5q0|7r8=Cw)ua*rbIdtxt2sal!Cn+?1|Lqc3AAypMbnsyWp6#JUFlgTXCx0u!iVQx@O*t7saYG9G$y6m z(Buh^SbZu|PQtIlsb4Uhjd>lbPX{F>9m2#V|<0I-QU;D$Pvk77a;`CC~@-ADN~CBSvx%9+RBb3to0@k(z|G z~M`%c!>nN^8_~RS1&kI4_ zIJmZ#?F?u-wY|NHskk8^u)Gn(0M; z$(d(%eAx}pA1*oXo`(*!@yAVTye6yMuI$lo%ziA#%T>Og?)0phm8WXO&7Xa8^rJjK z-*a}+*FUwrxaMHh(oxxyVq#(j#>6;()~xSbs$FwUN=#IVa0@D?e%~$5=+~+^rDLM~ zuQ@9^BnAeScTROk2z0LCRPLA%sD7I>q+>!j8n zd_Eo)P}#Y}Sbv6dvU8$;y;G@6qW^-E+9feur?Su2gM6P8Q!Cd0taGwUVxU|Vr}FIy z;qg^`zP4lqozZP${o9=twJHlYEI>@3I6+?)UJu)%dcI!_g3`!SAfD8yhY_=i<=l zZPVCrdo(%5MB>f+5B?b~}JC%DUgzu>xDLfiycA?3T$*CRd z|IInsJ2Bh^LcI!T)I)R75}Y%&5pYMWTC8_#ox_Q#6C2u$*4(YU6oX(LjgJlW zMXTvli-`}e_>*@yVvr;ZS{_uL)WKXLW^|2gL*SznOljpyomv7u5-Oao_C-S}`X zQVOS_>*r!LwN4YAW5Y+#=)Rqwq6CdB85i{(&CVTjy%A0QW0cy)hA*Ni)ZKLwuG7q` zCA&L?S`17(ot=oLJa<+?ucFm+&a7(~MZ#Om720^7x+5GKh!*Fr zsV7Kjtl8%9=p!^mxVt?BqS`vAMka)NFv40A*__b}5XwTY z=M0aJ53eVsRm;e;8=geF9gU6?Lkp;&v2&(XeE1+K&7v1I`8s(T5zKbg9?hE>28%&m zF(xs*)mpIbnHfJZtOR z_FZE`UC>yL4dcTzNhzA>3Io0a%?o@DxWBs_TU;MvNnKsc;gM*yDB~@@H_%kZ9Zvu6 zPNjPjLvdX7-TFgmq#8P_o^BXTLP1OqTg3W*a4Jno3{>jr44IS=?$^`vE#&rPDVlo5 zJ~JUU^qDkgRaQfPFK5W)gs|!54I3NOpxE$UG;Ipr;x5zMi%u>FOmiPJO(2$p`y4cl z3AM5S-}{S}{Z5~c&CTX@`-?UYO(W}-+k<9(qn4<Xb5+viKas%=D@a8--x z>+_Ajsx3#mmRF{q&o}yN-dwbMu4=iGe7;FnwHavF@c6wMxBu^<}!}qY)dnmp`B> zOt^~HiSrL}hD=Wg%^RW+WhMIGcTP@E3~e6j^R;l!Opg!whw)X2vub9;C=zX)RS(;Q z@;-%X;#w6R?(?;CQ~gP`aZ@jlN_0~tN2m^!=ts(}H?U!ZbBcz~Lv(YqbX(C&sc^PY z-XWJ2!0K#<*2%SakyHn#+QSW_NoWBQ+VnMsc;N~`?=TN%plLZ0hAjS-XtmMuIx&Rk z5j5>91>F$6CC#&pc6Z9oXqq=Rjqb7jN1T(h6T|Pr)q`WYr`K>wcPO4Cwt9@u7e!!~ zFkLDKiYq7rrPH0tk0yjCz_L8G&&=kWJtnfnYxRvp)9UlK+*i<=x|X_v{e*V)N)e7D zZX39HT$Tc9W1UlT5(0xVoXT?(!rL+;med)@Ho-Z?T}N})PED_}TCt%qXic3}4dO%V zNx3r`K1)iYh?j zv>$7HW_i9Glisp5YI1OErrW!)ECbJsc zx+aoRd~&T}c-}(0Y9IasEg@1@s9`34Ijfq*ho+Hg;S6sOAKpufJy`vqwX#_eZFG~k zXcVs-%G!x$UGB?#O^GzB3(!zB+YEcz3N$;jeYp!Avqv{l8d9(ArD)zv>zw`bRZX6>m>xMEp@n9l z-R*jRnv^%VvT8Qt>UvF!^UrXGEKLYU&-6|Y?j1(BJ({M5HHnuq(AuG~+F9TG(ORSB zbYr;W!`_9=I|&U&Q#po|>0XAWRl`nCE&I_Lp+&p#U1F9yBE)x3QtV({@(ro#uDuQh zC(*PocsGcp9`V)}Q^#)91Fe>uCv7@fb5CPL_M&NSnDUOX;as!5`3yR%2gF6A$k07E zgr7r`vmD`ja~wibbKWJT*rQ%^-i^TRXjRGcZiyzNX`k`7!q?F}H<>j5IcLT5iQy`9 zyhfR@>9OI_R$~}&?+vu}ZmXJ#oO8V)V%z8(8;GCloLZg`UIMA+*fY6H+=HgR(x0ZW z9ClW$;IQLxQFK3bFD%bsCwge$+45GwvS)9;)a79XBRswP(6?busrnl3spJvJ1zh|qLaWpMr@ zrG@C7`_s{GM`J$fv8$lfcgtuS{R1uDtAX=b{U;)MI<2Lld3o&gp;c(zoZ(&K!-2(K z?L1o|EUZFP#GQkty^zUf4edqq?h}GfdOYF6)xHs$7jv4%DQN0M*xgOHqs5{zsmo)- z`ImTk)K@PyaMu!N$eM)ktB_4SpNWa{XsV2OVbh6wiUK-`1Tvm-hOA8pJol8da&1C5 zb7^GUbkThoO-$i$;la>(>S109sQtW(j|bJ{#%0f^O}z&Z!Lv;h!PBiHw1)z04W1 zF(Eu++4Z$Nho+hLPOqP$Y30y^wAk=X&v~)qwh(HIR^J&uIX-azbIz$v3E?#mT6A1- zT5+5BT4K1-^Ik__n2!l)S6dHnLQC)(VyJ#Wlk+S%@G#t z3eTXa_imVlFQBP)_YON8|AM#V-TfxC39X~+aP}9yPI5zYZ(KBroTA~l*g)os&Z*i7 z;Wr>{mk7(tX!4Zyxx&V;@&?S?j>n^2U4?FUlySk9Iv zH$vM%MUgsJ4`kW@w6q24} zYpq5n7sf@SXj<9)=t0fZo}o8N!>s0BdP2+5y2~j&pnNMaT>aInBf;3GpxJ=v9UFQM zje7t(@Hr_t>0J?ST@#5&?L|G&ygSypq~xHxfYn$4s^2L*J9C4B_zWUMIb?MKeWY5sH&8{ksl{sDLrv(W3fC;9Dej_%NMY}dt;=SqRO+ntr~ zCj=gO(>e7~Lip=9y+z5DpTNk!BQp8Y+M#vAL#CTxdmPPMU84uZMWfUv%iVPX4c~Hx ze3B4e{FY}yKum}Ye~qSbWc^WBm7QKYVQ2NCxG0qV&Z_S5fh{|omHQI{XLmZM_9ukL zyzRvclgL%%RWz@S(NDw%j=$}!{4^o-z&nv8vXxYOcl=a;j$PgyGS38mV>IPa5drfs znns%EZJf`xSxYbPBAR-|hSeZ8(0jMD@?b*v+1-&iC&I#?qQzrEfU>Uhz8eW%6&U=k zv+__vcr#=-*F;a*%j~%tL1?LH%443<-a~7SMs&4`4drznszvhc;eK{Y)xWT%huYuF-%G-FQ6` zAAXvYHUy5T+~j`$p|kR6LU{7N$asye8yk3gpHunEgz)c>jj?p+Ak^q1j&px~A~Of7 zGX@MA(|HWdn47^KW!BoSo5(n>>#!$Q&noKCbCN>4l z8$VseHhtop`YIuG8nUXpXBFP>74^pH4z!LGva4H{92ye6`YlmUFc)(c+8GF#%u9?UUTs+Xc@zHJTag-3s%;G+u?z_CO`xG z;|ARAFv`5cT1YC{)yi&GcDJ&JGWkf#vtCxeUW)2%c}a~&A1nJ=9_h_kk|nN}qWW9@ zdZ~(%Eib9$AS(wW#f{?RJkok*}b96>tv<~aoeoiZsnUuEt0p9D!2=&&-GG0*kk$YrR?`w{(2b=zaL)m z2$KJtm#-9b-n$a*j>DI>%#Eb7j`5E+vQyUXdZ{+Qhga4an=dK;N2^O}@XjOU`!7~r zQ5-7cPYCVEVU_xSSmva@0@SO93)}i7)ozIZaY);~k`S7%verOS$?{g0)Cg2ZYIbT_ z{(7m=Z2+(O;;n3G?IhK~mPj?+&hqUtNvPp2Hlw@ExL&H^zVPZnf159-eZX@q*mBNR(}|&g7cAbaFNY_8mWe#LFyx^ax1Ma zDMwc!W%rWhZzRdj^u3IM8dzrwthaK5EhwpqHdI{LRr_2jh8|K8?H%KnVa|H<-_ z;(xZfWQg{Cmq^HgKdix@R;nB7Nsxb3FiMJ*ih*c!Igrcd=eF`@EAt?!%9qdT`H}ia zs=cD(bsZ>XiPA__SRToLzKT{>v9h{IK9Wkt@Q)m+YxOv!8f;+s1f)KavTJH(OUq08 zqnuTLc;|=qmX=h1J0MkEC#14&=O0zm9jW{tmhWx(yRDvN^ZQ#p*~%0vhgvxTsWme$ z$SkO#3X_l9i-E^cvdal(SE9V6@3w-85{9UTx ze0Vu%Y`&!U1y+|-auNT?Zn5RBm*SV${G~Sks?3DYB3f<@R$7A_Nj3a}&A*YL}`qxN(B$fP@f8_pmR-Ul@X=U>H zKO;4f=M_0>@Ddfsfh)G6|0H!1&8A8{G)runJU@@dVlCmp-RKuk#FR2U5ZAej7Eib9^)hu7j>a{a15od|| zNPQ%gOt8A78f!loMW_d~JEv2R$w+;y%ybhPvIogf!D-e&QUzxsMLlYD z2dRqZA$8$egjBi3NPYg#N#{xJxA{?kK1Er);q(9bPS{yz`@+>y{jKrPdM9{&CF@b908 ze=Gz&O#J8JpKjLvdHDCw!@qwX{{8dt&pjvn%frEc9{zdvEjN1Trx6pcgVpuV_{8Un zJh!+$LpMDCJp8-SLqHATKM()@dHDCw!$0q_$UhJNyoZGUJp5y0{QvRc-=P0*9{!p7 zW&H0o9`XB&W2?`sysTTzSL^@U;Q4xMy8c!=;dH`%i~Kzn{aky&*V|i^-L&dhICk^- zqMLtQ)9LUVKNn3-ANbg}CwEl)@$k26)@*2TtA9a-#=R$Yf9&h*JHNaA(2-w$O#N(g z$D!5Q-u37Mw>>gFko@K3W($6)_(|%QH(j~;T>B}hm0zl}Zr;+fUH0GEF=W{d!X~qLSI&hkA1ak@mIGnaem()H~+zao&E{B+Dl9ofHtbo`lVwTCf0;0%Dh_NdmW}EFIc8Msz5@L=Sy%Hkh z1&IA398=~6h>9;lOnm`jzS$?@poqFJLKrjUMTlvuAdZVzXku1D#JvPDe-*?cb4{hzlZ?m?kenw0;F**~<`1%{dX5M09%v;u*8_6^P}lAwsJmmYFWA zA$qmk;eeIgEusJj7TgPF1cV%kQC z<03Yhn2iu|n;_9Tj>9QH3=N5={BHl6nEfCRLA(FR1>^7@KY!p#&E5sg?v=t)d z4Tzm0_L{tJKor>qG4>6J56pHEyF`@V2C>hK-UgAe9b&(Tk4>5F5Eb8qn7SQezu70^ zpoqF}LL4wt-h`O81LC-dLndYiMBG~t^LIcTHpfJq5Ygf-h$CjsTM!F&LR=7W)HK-% z(fVzOWji5`nR6m8iRkt=#Mfr&+Yrm&fe5_=aoluy2cqXLh;<^qGyYu=(Yqm%cR`#q zt3_-SQE)fJX_K_u-^2gC*(7ns$5(y({h?l!-^$bX;P#92OC37s>)OOjdf#8f9N&wtmrcz3 zI3M=`&d+}z;#YG_#0e2CK7jb$%=rLf!G{nRMEq%*deN$aMJ#qUXmD>qKNX{*NJ|KY>X87$R&|i`Xcl;3p6{P0}Y2 zDf=OIipXX1?uRJyDXFphA#OI?MeGt${!@s&X7r~J83!Qti^y-v9Dt~J5Mt^9h=OLH zh=U^P9)u`trW}Nrb_n9Qh@vLu5JcQ(5c3Z~6gS62oDk9CGl-IA&Sww{4ntfJQOYzq z4AJ^?h-HT%%9wK^E{W*&IYe2r^mB;iM<7B+Aj+FAM<9BB0kKZRZN~ovMD$UJ=SWNMBT3;V$GDVA*Ou;aa=@w6Y~v3+;NEc-$2BhVz=@|Ni==@2zZf z>6N+^30?@L;@Xky+GE0^}GoUK9MA75_Ou-?4A z>+g&`RqWn3Z(6hDMACJqm+@xGWvZQag?5f#W(%1Rxb8R;_bc?7D>Q$PssAf>Cqyj% z6=IS(DPqBI5FLJl$TSOogJ}Ib#P1@em^QydToSSBcZmDVWf9B&favoF#8k854~U+B zLge}r;vv)PPk)d3(SclMi}dO9!+{?2H=;I@6En^9E7+&_1G(l84{-XKzbU}52FNez zN1ts{{SdoE>=iM`6b(RR1R*8`ARMz>M8znGYC(wkWAP6wzA!=#U*^sacpE;*yBpMLc8L zL_;hOL#&F1SY|GZ=$Rvs+uR)vwB_)#g1(#RoLJ<_fyD~bD+k0z5nDvOV8S^eQf`76 zo)cn~*(9P!E{KvhLA-2IZ-Uq*Vy}qRrf4pRjNA~DazU&yyG2yI8KPQlh;?Q{Zis^- zj)>S`D%}h*Ef2)3n;|xtLn7kxLNv+)@w%Cw2jYZ?Ga|N_`gtK1hMT$U_EDZ61Ni7VqOT=Cg`%KXy5E(@wCKZAB*z6Wj zu^2?Pq7eJdgrX1!MH~@vz*H&*F|9bntYQ#{%pnnRB_J9Vhd6Ae7l$|@;*5wRrhW;C z1tlRCmw-5GPKs!K3q*&K5Xa2Ik`R|f{4U~a)8-b4<)t82-2!pkTo%!@G(?|L5Z{>< zr68iqK;$Y7ankfE4Y5(g77?dSxC}(ftq{Y@K%6m~L=-6tQSw%ZA5H455W7U|6>-iK zEenxR4q{SSh@Z`F5f#f5metDYck-tmbbR$2x@$u3o`|{Yq!}vqQL(-pwyU8nI&ejVI zbbHu+yZ6_Ehaug!vF~x|{BL=GCb=5&=4)l1ax)`;@_05c%;wy{2xNB~-|%d|z|S2w z6uUR@ZjI<4UUz>1m9>Gt!rH3fzmA1Gn4V+fZ*q`deq}cgTn;qO^!@Rt_YtX=1pG)r zAL)7`t|C)K@OjeOh@b8<{4m;b`Wev-%ROZ|{ak60<(67bzbIPbay&iK8wo0?UyBrV zN&XPJHPmm~LiPtw&s$F4h~}`|a?9z*cR4M$0#459yW=cX%;!aGrypKzP$nO};o$yq zTt6Fo&62O!!px*^qUF}u!uk>AQlQUT%jp+bPrJ;uHz4#&zh^9`w;}jXe^A@E%yN1I zLL;0XWIk`nP1aDqtXyun*DY5NeTC(=*uwfX_e#rcwOnEJ7cBRN<%*!cXt`~c(~ZrUpwIVPk*D_N2Ix*oz|`-+GfkWZSC|E)NMdzcUikq zq~8Ym?1syspRSfh*&~L}$B-KJGJsHbKcCvdx1y8L)3EqNR1vX=YYa%@n(yl@J#BXIoZs{|rHpgU^qD#PVdclms2 zxhkaZqO1b%7@VqRXY<`{+sM>wF#M-?>3vC-JYfr0hZ|tIlW^)3TcB@{<@Ab-%JR;z zFV%8CS}q2zGn|6^oaJ~6+jqtWwO*eg2s8B;3w%FV@;s#KsiQ)cy9}p>>w=#w_q$hE z?;rav!FC6V98db7uw+} zXt~yKk>52JvRoTD^-cj=*m7-2t9RmxSgsxE$;_*Q(S2(P*&dwG`%{X>V%D$&=~pmR z;1#!AN7CyQ6nsipt`q6)mMaM-Ups@y&xT7`yDo4~VyB=jZMoY?>vzry+A`XIRnHwj zJyFzFu!dbpt0&@avs^dQ`hC74xuWH|lkTr5<5S6UJxHfmuCnEN!lhcSisgDK{#rw7 z6;y>(PkMtkmeadhnx{KKXIr?23~xY4J!<@%ETgtY!& z>U?!bsP2AXKWTm9kZL#yd}_J+mg^6v4NIQ}mK#8NjtcOJx7je-6Pvpfq1**^s=p{S#ZX8gsitA`O>3Zu# z@uZjVWS0TD!zp$;!@2M8$`ieyqfZxWIFWP#%jwNM6}|_YB&~qD1F7tLf!>N9fb3!I zCXxOfXu5h@ZZc{0TGQ1FPT@o6GktCCP~T|{v&hhk5Bl6?xhbUe`in-RkLB(oEypzy zdUa3^-mf%v>Um$wJwUpoJmu5Ra#Klb$DAY=k}UZkq$-oA{Vn$pX;mg}faRu<*4OZI zYM|w&la@28BiV8@Nb4OP*$=YZHeD?E+@)=mPY&bH7c6cvqJjg>H&MX?p(i1im=KVnL73=_Sft}!O z@UB@J3YHzRhU8kHZYm=6V&T)^8SpGv2A%`YgT-Jvmo(U_ICXHi6f` z>tHk30=9xTz;^H^*a3Eex4}DL7uXH7K0_=DeyGVA8^niuMW^VL}h@^a^-;DF)9ge0Xnzk z1v;zs3GwG(?uOLaOJ}WtKy-~*tO(kXgh5oCcS=ud$K;Bhby%munKK7f1>WPvH*KA<HPC6Rs#HACKPE_9joua-4 z-+>dLASeWm0{tC=Pr*TO7--|u&z0W?AAk?RKJXFv7<>ZsHx70H9k6tu8UzOT*=Glm z2m<}){Z63Yz!w3fKsitz+y*Lx93UsS3FHF$GbumN_&M+s_!(RP-<#dxU~J}j=7U#b zeAz)X2!k9TC)i2eyFh0wovGqML(mB5C9_JP3ec-J-+`0h6gUIUf)!vTcoDn|UIlBw zTA-uSdY!8_lGp@Z2V1}!U>nf6=}oW$yanC{?||pPVz3m<1M|USz<>o{A$S~&25BH2 z=shyMQ>J$VCj-4rs-w^V{j_Z$iDWPs=q#kOPg~FqvI!>JeJ%Rqri~a;m z7cdy4fU2Mxs1EW2{c)Zvv={n~e||CHT)}pk_rpCwT~7i%5zzstIcN$J!E*9ff)~Jx zU^$%LfBPBewX`GPQ?Ll=&AZ(h&F44NgHvwfp2u|c2C|u=xr2$BZE3e9SOulG6DNT>v{Mhn zf;dngGz8^A1#lbCZ!8OgBA^&30dz{xjawMx0PCo;I~W3V{z?Q*v1taHgGzeyRqq+M z0J_Q>umF@`jo*YLQ{a!FuLIk_yI>zE0cw!17f|y6-P{)hdV^Ls>wQ6g&7$^v8g8bkl-hT#kw9!#Ue;{Tk&|Rd?K!rh3P#ly1 zx@)`@lm!()MNkR+NZGUCJU9(>Gj~A?{w>e|5B2tIWe{no2%}IC=#V0 z`vK@>!H;!#uj2z@kQ3wr7a6Kgz;L`C z0Y-t*pe>_O4(Rtbm%-2A2cUzS&c(Y(zYSC_QYMPD?n0UYy=rzDyG7K|0>>zq=@xt# z@^5%2{#3cl3s>tPay zKqH`o_(h<@yZ)9^bD)E`4&I$X1JDkqS^?QaoK^><%Nd=sBhKk8-2>DG#lc@2XVluz zfPyIEb$cpm4Rk(Mh5eAX01acLQk{vFHwrn;o`Zj@X0GH7-nyZ5zF>hsn<%;>_uan* zLwY6yJ`U(d6W@culs=8rM))<*xj@(bkKl`dw@7D!%nf4;1n-Q_oI?6huncIE)n=)>IaeQ6Vz3AAC)0yBW>X5Y$m|Ekk$ z6zwQ$fp*t5;BoL2(5AK;JO^F@+Re24t^nGNp9jx^XTZ~7DOdswm-)G7N&d*W~^)6G<6Dy*Q`2qKM&*W9b}>$ymUa#D?G z%C-OvsT@=}N!1rAr}+BUH1n^F9X3-9MOJ|-Sq~J9Dya0kU^mzc-UB;93acu@Ynyxr zybZ+d0Uv<(ZCd(apjG-Qa=+&P6QDb=Js>;ShyD@x7#skHz(JrZ)#socHs6CUNFM=T z0)0>P74jH32~L3TfUauaB9DV_fc--0Pvu<%eBHRcbg*ou%d?H>UL_S?+l%fvwY|&$ z+G5hd-?x`ExDg;HxJ0=Rfwq|}q;B#vkU7W;1KrN(w&pTi6w-$bBL7er{EqS~cnAIp z@;4B$QhY!KfFJycu5{V!c%{YZjFAmVrM?hyIFQqQk?lZR5C`&sn}D89`o3IW|?>%36_=)564uXLo&BIQ9v zzQcNCqq0aHTy6!CLyS1(sjv`9S0=5)P9@7%L5drOZFOWVpiaoi7@(tb zeW0UrrjAWbKx2>ybZgoWL}E{8>_(s|Xa-tRsUWTuXdw=?26uzr1O0zE)?prc(k zq;7xj0G&Vw&_2NYcO(%x!*wAY%l!4BKu^*ukn_Nur0)V+41JLK;D#ZGf>baV+(zCY zq#W;uR4^tX`-1`CGWtMdGDrbKKt9@cy}Omn(GZU!Mkhnx(CksjQTf5w9>h@r>_k(0nE(o>LQkyDX_ zkYm6Dr0)gkr0+4i%LQv>{-r)>Rii3YR7LI~EguGhh=0;m&h>$Gqz)Pf8f&HXE0Uv`;K~WH?UvuHYhFiKj3}=zk}bvuiy%}3@(8^*hqI}6A}S#d;Gu$ zj+3dh7Dt3rTJav)i6@e-sV@up+`891QaRW=ShIRPbGmYHp}*#asa1mOZt|y@__$zE zUI;n10hZxM{`<_9 zzHWDu;t|`-IcXUC?Dz0J(Su=q?aKSgPD!nt(^4<~M(tih{Yy*`8YlR2gu z!&S_0O&H}fRX8wXn3Dd|pI2^vA+>=2?m7%}jGj=|Xc{b9cYIa%_ZwNS9T_tDmbIhj z<9;m+7`VpOJTJEAi@(sf{oFn7_`Cmagddto6fJ%j1J(V__pcS(R{HmSu0cH&oo!Y( z4G!jawndvER+uTxa4DvSd7@cxP#~$MiE18vU-FaY!S?(K4uQJ0&8QZP!5UNJ zErx5W+0r6dyFd%V>n7T`oa@$g1sgwgHsG&c$3(RZHsH6Ri7kV*iyyHDM;?BAPR^UM zR}1(F5%rI6o)i$p^|gCWYKWfREc?-Cp5`Zjkq*u<+c60Ai#4COBzT9K3oU~u{S(a5 zR>2Pb2TZlrhy~`J*38q>=H=GGqV-;4R<(czt??Znck-5Z0)9JITx`6-dMGrv;^Fwi zhiQe8&{%}y%pa|TwF3F$OszI_cY?`mL;t3kq>;gzW_O!lNoxPD4Q=f(M|uZ~nvQLQ zDS>hg&0UY+)Nr$}ErZj$ktyAdC0IJa>rD49dpaiNS&IXaW~wBZuI+;D1Emwq)9r$T z_;vTpUNkeqEbE2;3(TQj!4Aa>HSxUc*6;g2uRNM`(H#rzKfaI68|@j3K26PM?Qynp zGn2am;WMh4*Wsw1wYu)jwsI#0>UzWbrfJfF`WKix5jU>b-5ai$*|HmNX5E3^)D~WS zWj~#U`oi=z0=(x1yrf6qIu46m%L}x~>Pdjg!POS9f$q&nHq-Dhk z4f{NcL4n%sO;nd)tr88}b9cogf3R?9qm&s}9>PZ(Qk~kHr@F9V4CxXq_V3K7(KGu` z6~%WnKTuJibw?9@J00rT(KNiB;U3h{o1Z~53wNtwYVf;SVwIK8X-|DCkj)*ck!Jes zjLKg^q|hxGO|->>KQtS0TaJ9qDPG&_^4`(RO%Ki`R^KISiQzrKl8iMK$iKMroHBBd+ii5N!?jZo+D;KcbxKS zj&e)mNg?y~HH$!@+f9icjQYQEj6z=V5UJ9)n;|{eoowand$>K`*Ml{~o?N;olleEv zOKf>(2lL6_N%2 zBS615OMB8z@2+MuhSV#SpKbqm9jjfeT(5t#?n^A~?(NjC*MFmV(&*PKUkeOhoN3yd ze!XDE_72vrd&51Sb4V@UTB^`C8v5+l7QrG1h&vo{_%M81l z8GGa|9^c@Euke9S-_0!dYZMn@Z^pKpC3kbV_}LnK^X-Kb<>RW1zGhH?XAvyetd^$S zqRmND`(DfG*~k2#%BNz%l_YxMkJDM8-g;TsOvqf6hQqT2_zc1j| z^8$VBtX%ER2D6W+L|8=zfb_S0a+kjJaL%D->o7d??u7znhMEtDu-xkoHIGs-&|#?Q_yV%uP;<-Mm}Qt_ zDGbOg^JgmJIg=Od?}Z{pf34E8=Is=w)mGz)NO@B|m8?_d=H1k3{R%{nFq2dN)xZD6 zpTGC%Z)KL5E^l9R-ntZMGtx|6`7iB79Jc+wVbA<;nkg?_8=FI>fh?K4vxkm)=``?dI)bsu(%r|eS*C1a)z3yWD(bGbS~?uAJ;uC0io2(0#_(L8XkN7N-D0DM^MamEBJMHEvoF4yFIjogo7H^hZ}k)R zjGo~dxF??7rqgID{Kgy`i?9t}F^eJV0ULRm$dkcK`Mwh2B3m z$>wnJtTWDhKbm0pi=*{gVxN!pb2onMRPlT6=!reY2pyGrlA{aXnStM&yg2Qi_HIq? z5*<9wj7Vc0O&(_+ox*~giDe-yZ;pEMtG=~LWZ53LFI~VbQCDFwi=4dFl~JwA>3b^|JK^TI z)B5Ci^95y#ufjsl0+#=j@lel&Wj44LwRGS7rpc=b{mfKBlsJ!_#{c6};}3patkcWa zyvmkg`i;elk{Nt0gT<6*cjWslYF5K*7Inx`*-*YQ8=qR#@^PC}moGFj%uAFFbjvV# z?giuga9j;L>FS zE?^yrgla^$i@5SkzmFMIJ1I-Nw)O_OTMWGuF)s zU93qgsBD2x9&WbvxjkoW4)eKglG#dGZ{ZXQF=O836|s|8#M>XP&nf91UkB3-1aEB>)GGD-G0$ePG-f_% zwq+4ZUb)CzL>8jm3%x6xE<3Ixwm;U$E9y4xb=rGaaN7KNf3UEc^Lpd$2Rz)JW~$!D z(pYDg##0M()GM{=;UBN9p-3=CoUl8SS#cjX*;i-Ay}o+e|6iTA*Mu8d{)Y?f4F=im zg1wd($nIY3BBRKz=3R}7|C>vWI~DF|d3Ghn&F~g_`J}P8b{?I!nEu*lBoEFoA3nfz zKR&~pdLTIHzgreRL|wYf4X=3RY|ML=c%IIwI98XUAI*}foCvO9py!1-#|_ThfAo(k z7}x{#zjx!Vhs_UD*^zEwp)&wWE8i^dnt3I0SI5yM9^y`#hiE)TnE z3Qh^MnQb0<$yES^qwAU@LwNsdkc#Bm_HSUy7Pe z%)4)2w(k2bVXrV^F#i3wQ6m?cC#k9Ezx`IqtX|ElG^b_;C+3)D{V@y8h=-Z%r3=l| z5A&GY{XVJ#-*YsY#b{l@N+EWjP~}-mFI8IOdhK2^q8~SDvp6#5ecTJ`&a0~IYy7SM zh-*<>7vP?cn{8MWPr*XtIrqcK{Xa~&xv;IH9$)d8T#wMmWLw1#FK;Px+V^8ieJSGJ zqxz;jZoc4Yx_xBYKG3I~S@{UgTK@{LHqmjThji{O2!=eBE6|{} zM)qHy3ryDi1%3I~04K+7$tz#_zm)&p9GlIT9tn%RAUI#WVy@qw8TcDRVZYTmZ)!Zs zLA=9a)ArF|7LP~wJj%1V>`P3sIc#awTYF*k+kv)$7G2+;Mma)39lc|Td14Ni1GB`N zsB>q_zwvbKdV8_Z6KF0U%a)iAvEYwmoSehG*|#QkF4yD>X6RgoKCsj~B+XvfD&?o* zD{BP&lWWm0#vXB?%DsNk!z2NvfAP}-ypt9EJbuih1BY%10rv8nWpwIOudVidew4(86cTQGh?B+ z#BL~=gi66yKt;R)3hIEspeT>=0V0A#ceK>d%GV7IT(0Vt;{BcP`^MpAxA|x0%-Lt3 zz4zJQ+57zVS)agikfi9MVMz{yK*fC$6e*0NXSIsA9_%a5VxOQFN?s*_(kl(Fb~8s% z+V6Yge&-K=Q?b2J@X2;krg6S@RuZ3FGGhQYWnInW?ay!W-%vaVLBE|aT$4`?1XW`5g{^pR+Rj#IkL5FXWqC(fpHK2_ zSkYuq@OxCh+t1H=yRM#h6`o^yKF!|-!-;W1l9Nw6w*kq`JwUD7P`B|rNTJ)g5Shy% zVU7W}7mj)*E9rM|5CcLBm2Zc4ouZ$&!@Jzff_J%nxp{j% z^uq_dKD@>c(8K)ibah11;tiLV@wPzi8<%8C=wK#{&6k@;NQRWqgG_E6D^#uBfk}iy z)dae-gWDrZDigF=cHvuH=Bz%ec>YKSaOZ+Dc0#n&GCIE#3(40@hmG+Eyw>x%;vaO( zTtTCD!9q7^!7j%tk8C?CM5W5jX#);TXx%93mx6x)5wD|!UEJF;l_^SPFd_q5;<;jd z;F4BXR?p*irgj>*8z9S@I@CHq9$NVF+RqNBe93@yUQ?(4&?_MDAGku;h07mIv8Kjs zEp!m{(+Y>{>m8%N>z~^U53>*Trq3}nV56rHe8ZoAr|zwdM{^wno?to@vyOMuI7fb8 zIn2=ml<@LyINQu)!q|e?lN*M=;XTDc0sPQ48zFNED26e~pKlwyXnsSZgF=rU8G4pF z?Hl~x|8D-+(F45eU5u5*VtzJu=%AEwE?>ps%x)LmN?Wt>aBQM{e91ls-3ZV%v@T6s zSs+0*+D?~6Eg=W{IV;I+8qiNVO_lAZFdfY z*V8-(9`*__%6eK2Udel%fH~roO$_Ojdq6V=%T)|X-Zy!t<|3XTkxm4a?E-fd&90Ux zOLrkQ(a%gm0qpz}Sp*1Gl!f%UIApG-O}P%U;r&&WotpyoOoQ?sW6pTb;EX)X)jPV| zMG%phh`Ne6_+K|fR~T8u+U@4)I(>J02wK>Y_ug0AjyCtMP65M7GWaJefC0{esv)>$_EsT0 zSBOo0+4*kXXiVK8K|M$fwz!^fc`#LQupZ@~a}`4pYyN$6?GCa)yrKn@kzp zFc%*dp6Lu}4}(JNk<6_l8`|B>CmC{S;>}qHP}SE5SVadit&e z-EsA_x)iB$a=id1fBeky=0WfO;>%lv&%bun(}Pk-vcI0(EKpK_Zidl&7A_Fn$iijF zdLD`=d#qXG0egNybIagCs~ae)Oh}1J%aHu`8~_XP$;a^qAPq&GZ%aLl% z0R@ZxzIQ{_eP^xM&X45*ig%mnayf)Efr2GqiiHcGT9P`Y(qV(6P2_qEi*T!%W*tK! zc&}NIBWSiNJB%B?girhVWqa661)xAVxv3J@GWfcHQ%`cZA5Xsf-{f^%Smig4gR#~o z9>lyGIGbrV8pkRt#nK|R~l?A`=V>zflJM=jv+vvyR5Hj6H?iE<{ z{WeOf2Jgc*T33PpD{NGZZ}IAzq|Qc?O8kAVnI@iqeR`ru>|D!|+eB9USQS&>A!=I{9*<6KCOTcL#$F;^*`q;L9GV27-9?e?PlvmF5`cEF<87lD-4<>~$9S z=o=~I3}=d8g!{3~rxJqv>-)q$-C;5+w7LkDQ^KME^^n@{-pxY)K=h}UjxxI?n#bph z?NvugUtCb%cCi#~76{*dbzy_S8oc?G*dNqCI6FIkw%2*F-+bkxXJ^ckooPXvomXR? z+v2vidPRKp9sI$PS4ynfTU+SU@Ca=;wD*5?cjtlkUaA^~d$=rzufN@5jf?!E?j^KY zWC>M=E*+3iZ1qKZ6x#6_Q!d=H&dt&2!lRT>uz%jUTkDp!y)zsS6jSh**N6L*ySN9w zClWlIxGe4L=x5uL$AW-uLf3verPL(4*Q}?eI=s>(=`{f`%)U_KTG%XKy9aG%h^?27 zq{}lm4n2rA+ZOKR_j~38&GkR3(Pnkkn}4sXdH+)XkD`DoFt(f4E_&sQv3m^$w3*_M zG8?>p-ZG+no!DQgGJEzt`(xW@V*d|UmB~k@sV5X}!yioWA1;I*o3Boa`4`%*Xzv}9 z>YVVm*&k)G7n0y}q=?ebat$s@A0M9xA0N`ybMnWH>g$}GstTlIof+mb$zrSLLOrC| zXC{$8O*)kBCraJOHAvc@mfzt%iI0pnO^7m?^u{UP-uNB0GR!Mnr}0+nR%#;*s}u$! zei|ZG3Zp5)3;kn14_D6me^ zTJiV$Mx8cVYk6>odviWn)=P)DV3e0Bay3=8A|X%*`i2MkMo^QBRBo9$O?q=Y2YA<_ zh>)s0<8hsyQ9eO-qf)I>M8@dClri4??{J;gWKf2ijJyVc0f8#DZ$Ma>GAJl4A}oAT zc(7XK8#pOQ={GreQn)fqrS=Q=4Gfqbsnr>yjb3_9H!e}M=NvbZiq}iS<2%jOb*jHQ zOD6^j{, Version ". /// - The version is obtained from `package.json` using the `ffi` cheatcode: /// https://book.getfoundry.sh/cheatcodes/ffi - /// - Requires `jq` CLI tool installed: https://jqlang.github.io/jq/ + /// - Requires the `jq` CLI installed: https://jqlang.github.io/jq/ function constructCreate2Salt() public returns (bytes32) { string memory chainId = block.chainid.toString(); string[] memory inputs = new string[](4); diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index 44d1b9641..e98c688fb 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -15,7 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 3. {SablierV2LockupLinear} /// 4. {SablierV2LockupTranched} contract DeployCore is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast(address initialAdmin) public virtual @@ -30,7 +30,7 @@ contract DeployCore is BaseScript { (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx(address initialAdmin) public virtual @@ -55,8 +55,8 @@ contract DeployCore is BaseScript { ) { nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); } } diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 3f52967b2..012e1294c 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -14,7 +14,7 @@ import { BaseScript } from "./Base.s.sol"; /// 2. {SablierV2LockupLinear} /// 3. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor @@ -31,7 +31,7 @@ contract DeployCore2 is BaseScript { (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor @@ -59,8 +59,8 @@ contract DeployCore2 is BaseScript { SablierV2LockupTranched lockupTranched ) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); } } diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 22eaddabf..a20dc6540 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -17,7 +17,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - /// @dev Deploy using Forge. + /// @dev Deploy via Forge. function runBroadcast(address initialAdmin) public virtual @@ -32,7 +32,7 @@ contract DeployDeterministicCore is BaseScript { (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); } - /// @dev Deploy using Sphinx. + /// @dev Deploy via Sphinx. function runSphinx(address initialAdmin) public virtual @@ -58,8 +58,8 @@ contract DeployDeterministicCore is BaseScript { { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxTrancheCount); } } diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 83d78b6ca..36232a624 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -16,7 +16,7 @@ import { BaseScript } from "./Base.s.sol"; /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor @@ -33,7 +33,7 @@ contract DeployDeterministicCore2 is BaseScript { (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor @@ -62,8 +62,8 @@ contract DeployDeterministicCore2 is BaseScript { ) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxTrancheCount); } } diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index d8b2a9e65..78dfbe962 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -9,7 +9,7 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -22,7 +22,7 @@ contract DeployDeterministicLockupDynamic is BaseScript { lockupDynamic = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -43,6 +43,6 @@ contract DeployDeterministicLockupDynamic is BaseScript { returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxSegmentCount); } } diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index 47dc07651..81ca7ffcb 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -9,7 +9,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -22,7 +22,7 @@ contract DeployDeterministicLockupLinear is BaseScript { lockupLinear = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index 08a3e550c..148a3023f 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -9,7 +9,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupTranched is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -22,7 +22,7 @@ contract DeployDeterministicLockupTranched is BaseScript { lockupTranched = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -43,6 +43,6 @@ contract DeployDeterministicLockupTranched is BaseScript { returns (SablierV2LockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxTrancheCount); } } diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index 21de03352..6cdde5c09 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -8,12 +8,12 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = _run(); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = _run(); } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index 73ee2f387..fca805329 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -7,7 +7,7 @@ import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupDynamic is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -20,7 +20,7 @@ contract DeployLockupDynamic is BaseScript { lockupDynamic = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -40,6 +40,6 @@ contract DeployLockupDynamic is BaseScript { internal returns (SablierV2LockupDynamic lockupDynamic) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxSegmentCount); } } diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index 4690ab9a3..c7a4bb85c 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -7,7 +7,7 @@ import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupLinear is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -20,7 +20,7 @@ contract DeployLockupLinear is BaseScript { lockupLinear = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 1c5c97878..520a659ad 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -7,7 +7,7 @@ import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupTranched is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -20,7 +20,7 @@ contract DeployLockupTranched is BaseScript { lockupTranched = _run(initialAdmin, initialNFTDescriptor); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor @@ -40,6 +40,6 @@ contract DeployLockupTranched is BaseScript { internal returns (SablierV2LockupTranched lockupTranched) { - lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxTrancheCount); } } diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index 2649b5159..32bfeebff 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.s.sol @@ -6,12 +6,12 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployNFTDescriptor is BaseScript { - /// @dev Deploy using Forge CLI. + /// @dev Deploy via Forge. function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = _run(); } - /// @dev Deploy using Sphinx CLI. + /// @dev Deploy via Sphinx. function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = _run(); } diff --git a/script/GenerateSVG.s.sol b/script/GenerateSVG.s.sol index 1ee151a7b..9a3b63b98 100644 --- a/script/GenerateSVG.s.sol +++ b/script/GenerateSVG.s.sol @@ -38,11 +38,11 @@ contract GenerateSVG is BaseScript, SablierV2NFTDescriptor { assetAddress: DAI.toHexString(), assetSymbol: "DAI", duration: calculateDurationInDays({ startTime: 0, endTime: duration * 1 days }), - sablierAddress: LOCKUP_LINEAR.toHexString(), progress: stringifyPercentage(progress), progressNumerical: progress, - status: status, - streamingModel: "Lockup Linear" + sablierAddress: LOCKUP_LINEAR.toHexString(), + sablierModel: "Lockup Linear", + status: status }) ); } diff --git a/slither.config.json b/slither.config.json index 918d41bd7..edcc0bbb4 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,9 +1,10 @@ { "detectors_to_exclude": "naming-convention,reentrancy-events,solc-version,timestamp", - "filter_paths": "(node_modules,test)", + "filter_paths": "(node_modules/,test/)", "solc_remaps": [ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@prb/math/=node_modules/@prb-math/", + "@sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry/", "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 53bbdf28a..13a28d69d 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -49,7 +49,7 @@ contract SablierV2LockupDynamic is /// @inheritdoc ISablierV2LockupDynamic uint256 public immutable override MAX_SEGMENT_COUNT; - /// @dev Stream segments mapped by stream ids. + /// @dev Stream segments mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. mapping(uint256 id => LockupDynamic.Segment[] segments) internal _segments; /*////////////////////////////////////////////////////////////////////////// @@ -106,7 +106,7 @@ contract SablierV2LockupDynamic is notNull(streamId) returns (LockupDynamic.StreamLD memory stream) { - // Retrieve the lockup stream from storage. + // Retrieve the Lockup stream from storage. Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. @@ -119,9 +119,9 @@ contract SablierV2LockupDynamic is asset: lockupStream.asset, endTime: lockupStream.endTime, isCancelable: lockupStream.isCancelable, - isTransferable: lockupStream.isTransferable, isDepleted: lockupStream.isDepleted, isStream: lockupStream.isStream, + isTransferable: lockupStream.isTransferable, recipient: _ownerOf(streamId), segments: _segments[streamId], sender: lockupStream.sender, @@ -145,7 +145,7 @@ contract SablierV2LockupDynamic is LockupDynamic.Segment[] memory segments = Helpers.calculateSegmentTimestamps(params.segments); // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps( + streamId = _create( LockupDynamic.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, @@ -168,7 +168,7 @@ contract SablierV2LockupDynamic is returns (uint256 streamId) { // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps(params); + streamId = _create(params); } /*////////////////////////////////////////////////////////////////////////// @@ -176,7 +176,7 @@ contract SablierV2LockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup - /// @dev The streaming function is: + /// @dev The distribution function is: /// /// $$ /// f(x) = x^{exp} * csa + \Sigma(esa) @@ -184,25 +184,25 @@ contract SablierV2LockupDynamic is /// /// Where: /// - /// - $x$ is the elapsed time divided by the total time in the current segment. + /// - $x$ is the elapsed time divided by the total duration of the current segment. /// - $exp$ is the current segment exponent. /// - $csa$ is the current segment amount. - /// - $\Sigma(esa)$ is the sum of all elapsed segments' amounts. + /// - $\Sigma(esa)$ is the sum of all vested segments' amounts. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the start time is in the future, return zero. - uint40 currentTime = uint40(block.timestamp); - if (_streams[streamId].startTime >= currentTime) { + uint40 blockTimestamp = uint40(block.timestamp); + if (_streams[streamId].startTime >= blockTimestamp) { return 0; } // If the end time is not in the future, return the deposited amount. uint40 endTime = _streams[streamId].endTime; - if (endTime <= currentTime) { + if (endTime <= blockTimestamp) { return _streams[streamId].amounts.deposited; } if (_segments[streamId].length > 1) { - // If there is more than one segment, it may be necessary to iterate over all of them. + // If there is more than one segment, it may be required to iterate over all of them. return _calculateStreamedAmountForMultipleSegments(streamId); } else { // Otherwise, there is only one segment, and the calculation is simpler. @@ -220,15 +220,15 @@ contract SablierV2LockupDynamic is /// bounds" error. function _calculateStreamedAmountForMultipleSegments(uint256 streamId) internal view returns (uint128) { unchecked { - uint40 currentTime = uint40(block.timestamp); + uint40 blockTimestamp = uint40(block.timestamp); Lockup.Stream memory stream = _streams[streamId]; LockupDynamic.Segment[] memory segments = _segments[streamId]; - // Sum the amounts in all segments that precede the current time. + // Sum the amounts in all segments that precede the block timestamp. uint128 previousSegmentAmounts; uint40 currentSegmentTimestamp = segments[0].timestamp; uint256 index = 0; - while (currentSegmentTimestamp < currentTime) { + while (currentSegmentTimestamp < blockTimestamp) { previousSegmentAmounts += segments[index].amount; index += 1; currentSegmentTimestamp = segments[index].timestamp; @@ -245,20 +245,20 @@ contract SablierV2LockupDynamic is // time as the previous timestamp. previousTimestamp = stream.startTime; } else { - // Otherwise, when the current segment's index is greater than 0, it implies that the segment is not + // Otherwise, when the current segment's index is greater than zero, it means that the segment is not // the first. In this case, use the previous segment's timestamp. previousTimestamp = segments[index - 1].timestamp; } - // Calculate how much time has passed since the segment started, and the total time of the segment. - SD59x18 elapsedSegmentTime = (currentTime - previousTimestamp).intoSD59x18(); - SD59x18 totalSegmentTime = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); + // Calculate how much time has passed since the segment started, and the total duration of the segment. + SD59x18 elapsedTime = (blockTimestamp - previousTimestamp).intoSD59x18(); + SD59x18 segmentDuration = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); - // Divide the elapsed segment time by the total duration of the segment. - SD59x18 elapsedSegmentTimePercentage = elapsedSegmentTime.div(totalSegmentTime); + // Divide the elapsed time by the total duration of the segment. + SD59x18 elapsedTimePercentage = elapsedTime.div(segmentDuration); // Calculate the streamed amount using the special formula. - SD59x18 multiplier = elapsedSegmentTimePercentage.pow(currentSegmentExponent); + SD59x18 multiplier = elapsedTimePercentage.pow(currentSegmentExponent); SD59x18 segmentStreamedAmount = multiplier.mul(currentSegmentAmount); // Although the segment streamed amount should never exceed the total segment amount, this condition is @@ -283,10 +283,10 @@ contract SablierV2LockupDynamic is unchecked { // Calculate how much time has passed since the stream started, and the stream's total duration. SD59x18 elapsedTime = (uint40(block.timestamp) - _streams[streamId].startTime).intoSD59x18(); - SD59x18 totalTime = (_streams[streamId].endTime - _streams[streamId].startTime).intoSD59x18(); + SD59x18 totalDuration = (_streams[streamId].endTime - _streams[streamId].startTime).intoSD59x18(); // Divide the elapsed time by the stream's total duration. - SD59x18 elapsedTimePercentage = elapsedTime.div(totalTime); + SD59x18 elapsedTimePercentage = elapsedTime.div(totalDuration); // Cast the stream parameters to SD59x18. SD59x18 exponent = _segments[streamId][0].exponent.intoSD59x18(); @@ -313,27 +313,24 @@ contract SablierV2LockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @dev See the documentation for the user-facing functions that call this internal function. - function _createWithTimestamps(LockupDynamic.CreateWithTimestamps memory params) - internal - returns (uint256 streamId) - { - // Checks: check the broker fee and calculate the amounts. + function _create(LockupDynamic.CreateWithTimestamps memory params) internal returns (uint256 streamId) { + // Check: verify the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); - // Checks: validate the user-provided parameters. - Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.segments, MAX_SEGMENT_COUNT, params.startTime); + // Check: validate the user-provided parameters. + Helpers.checkCreateLockupDynamic(createAmounts.deposit, params.segments, MAX_SEGMENT_COUNT, params.startTime); - // Load the stream id in a variable. + // Load the stream ID in a variable. streamId = nextStreamId; - // Effects: create the stream. + // Effect: create the stream. Lockup.Stream storage stream = _streams[streamId]; stream.amounts.deposited = createAmounts.deposit; stream.asset = params.asset; stream.isCancelable = params.cancelable; - stream.isTransferable = params.transferable; stream.isStream = true; + stream.isTransferable = params.transferable; stream.sender = params.sender; stream.startTime = params.startTime; @@ -342,24 +339,24 @@ contract SablierV2LockupDynamic is uint256 segmentCount = params.segments.length; stream.endTime = params.segments[segmentCount - 1].timestamp; - // Effects: store the segments. Since Solidity lacks a syntax for copying arrays directly from + // Effect: store the segments. Since Solidity lacks a syntax for copying arrays of structs directly from // memory to storage, a manual approach is necessary. See https://github.com/ethereum/solidity/issues/12783. for (uint256 i = 0; i < segmentCount; ++i) { _segments[streamId].push(params.segments[i]); } - // Effects: bump the next stream id. + // Effect: bump the next stream ID. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. nextStreamId = streamId + 1; } - // Effects: mint the NFT to the recipient. + // Effect: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit amount. + // Interaction: transfer the deposit amount. params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); - // Interactions: pay the broker fee, if not zero. + // Interaction: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { params.asset.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee }); } diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index cf6db6f6f..6051b7365 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -43,7 +43,7 @@ contract SablierV2LockupLinear is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @dev Cliff times mapped by stream ids. + /// @dev Cliff times mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. mapping(uint256 id => uint40 cliff) internal _cliffs; /*////////////////////////////////////////////////////////////////////////// @@ -95,7 +95,7 @@ contract SablierV2LockupLinear is notNull(streamId) returns (LockupLinear.StreamLL memory stream) { - // Retrieve the lockup stream from storage. + // Retrieve the Lockup stream from storage. Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. @@ -134,20 +134,18 @@ contract SablierV2LockupLinear is LockupLinear.Range memory range; range.start = uint40(block.timestamp); - // Calculate the cliff time and the end time. It is safe to use unchecked arithmetic because - // {_createWithTimestamps} will nonetheless check that the end time is greater than the cliff time, - // and also that the cliff time, if set, is greater than or equal to the start time. + // Calculate the cliff time and the end time. It is safe to use unchecked arithmetic because {_create} will + // nonetheless check that the end time is greater than the cliff time, and also that the cliff time, if set, + // is greater than or equal to the start time. unchecked { - // If the cliff duration is greater than zero, calculate the cliff time. if (params.durations.cliff > 0) { range.cliff = range.start + params.durations.cliff; } - range.end = range.start + params.durations.total; } // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps( + streamId = _create( LockupLinear.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, @@ -169,7 +167,7 @@ contract SablierV2LockupLinear is returns (uint256 streamId) { // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps(params); + streamId = _create(params); } /*////////////////////////////////////////////////////////////////////////// @@ -177,7 +175,7 @@ contract SablierV2LockupLinear is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup - /// @dev The streaming function is: + /// @dev The distribution function is: /// /// $$ /// f(x) = x * d + c @@ -191,14 +189,14 @@ contract SablierV2LockupLinear is function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { // If the cliff time is in the future, return zero. uint256 cliffTime = uint256(_cliffs[streamId]); - uint256 currentTime = block.timestamp; - if (cliffTime > currentTime) { + uint256 blockTimestamp = block.timestamp; + if (cliffTime > blockTimestamp) { return 0; } // If the end time is not in the future, return the deposited amount. uint256 endTime = uint256(_streams[streamId].endTime); - if (currentTime >= endTime) { + if (blockTimestamp >= endTime) { return _streams[streamId].amounts.deposited; } @@ -207,11 +205,11 @@ contract SablierV2LockupLinear is unchecked { // Calculate how much time has passed since the stream started, and the stream's total duration. uint256 startTime = uint256(_streams[streamId].startTime); - UD60x18 elapsedTime = ud(currentTime - startTime); - UD60x18 totalTime = ud(endTime - startTime); + UD60x18 elapsedTime = ud(blockTimestamp - startTime); + UD60x18 totalDuration = ud(endTime - startTime); // Divide the elapsed time by the stream's total duration. - UD60x18 elapsedTimePercentage = elapsedTime.div(totalTime); + UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); // Cast the deposited amount to UD60x18. UD60x18 depositedAmount = ud(_streams[streamId].amounts.deposited); @@ -236,52 +234,49 @@ contract SablierV2LockupLinear is //////////////////////////////////////////////////////////////////////////*/ /// @dev See the documentation for the user-facing functions that call this internal function. - function _createWithTimestamps(LockupLinear.CreateWithTimestamps memory params) - internal - returns (uint256 streamId) - { - // Checks: check the broker fee and calculate the amounts. + function _create(LockupLinear.CreateWithTimestamps memory params) internal returns (uint256 streamId) { + // Check: verify the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); - // Checks: validate the user-provided parameters. - Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.range); + // Check: validate the user-provided parameters. + Helpers.checkCreateLockupLinear(createAmounts.deposit, params.range); - // Load the stream id. + // Load the stream ID. streamId = nextStreamId; - // Effects: create the stream. + // Effect: create the stream. _streams[streamId] = Lockup.Stream({ amounts: Lockup.Amounts({ deposited: createAmounts.deposit, refunded: 0, withdrawn: 0 }), asset: params.asset, endTime: params.range.end, isCancelable: params.cancelable, - isTransferable: params.transferable, isDepleted: false, isStream: true, + isTransferable: params.transferable, sender: params.sender, startTime: params.range.start, wasCanceled: false }); - // Effects: set the cliff time if it is greater than 0. + // Effect: set the cliff time if it is greater than zero. if (params.range.cliff > 0) { _cliffs[streamId] = params.range.cliff; } - // Effects: bump the next stream id. + // Effect: bump the next stream ID. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. unchecked { nextStreamId = streamId + 1; } - // Effects: mint the NFT to the recipient. + // Effect: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit amount. + // Interaction: transfer the deposit amount. params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); - // Interactions: pay the broker fee, if not zero. + // Interaction: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { params.asset.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee }); } diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index 9625b5249..d39df2eb6 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -44,7 +44,7 @@ contract SablierV2LockupTranched is /// @inheritdoc ISablierV2LockupTranched uint256 public immutable override MAX_TRANCHE_COUNT; - /// @dev Stream tranches mapped by stream ids. + /// @dev Stream tranches mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. mapping(uint256 id => LockupTranched.Tranche[] tranches) internal _tranches; /*////////////////////////////////////////////////////////////////////////// @@ -90,7 +90,7 @@ contract SablierV2LockupTranched is notNull(streamId) returns (LockupTranched.StreamLT memory stream) { - // Retrieve the lockup stream from storage. + // Retrieve the Lockup stream from storage. Lockup.Stream memory lockupStream = _streams[streamId]; // Settled streams cannot be canceled. @@ -103,9 +103,9 @@ contract SablierV2LockupTranched is asset: lockupStream.asset, endTime: lockupStream.endTime, isCancelable: lockupStream.isCancelable, - isTransferable: lockupStream.isTransferable, isDepleted: lockupStream.isDepleted, isStream: lockupStream.isStream, + isTransferable: lockupStream.isTransferable, recipient: _ownerOf(streamId), sender: lockupStream.sender, startTime: lockupStream.startTime, @@ -140,7 +140,7 @@ contract SablierV2LockupTranched is LockupTranched.Tranche[] memory tranches = Helpers.calculateTrancheTimestamps(params.tranches); // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps( + streamId = _create( LockupTranched.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, @@ -163,7 +163,7 @@ contract SablierV2LockupTranched is returns (uint256 streamId) { // Checks, Effects and Interactions: create the stream. - streamId = _createWithTimestamps(params); + streamId = _create(params); } /*////////////////////////////////////////////////////////////////////////// @@ -171,7 +171,7 @@ contract SablierV2LockupTranched is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc SablierV2Lockup - /// @dev The streaming function is: + /// @dev The distribution function is: /// /// $$ /// f(x) = \Sigma(eta) @@ -179,30 +179,33 @@ contract SablierV2LockupTranched is /// /// Where: /// - /// - $\Sigma(eta)$ is the sum of all elapsed tranches' amounts. + /// - $\Sigma(eta)$ is the sum of all vested tranches' amounts. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { - uint40 currentTime = uint40(block.timestamp); + uint40 blockTimestamp = uint40(block.timestamp); LockupTranched.Tranche[] memory tranches = _tranches[streamId]; - // If the first timestamp in the tranches is in the future, return zero. - if (tranches[0].timestamp > currentTime) { + // If the first tranche's timestamp is in the future, return zero. + if (tranches[0].timestamp > blockTimestamp) { return 0; } // If the end time is not in the future, return the deposited amount. - if (_streams[streamId].endTime <= currentTime) { + if (_streams[streamId].endTime <= blockTimestamp) { return _streams[streamId].amounts.deposited; } - // Sum the amounts in all tranches that precede the current time. + // Sum the amounts in all tranches that have already been vested. // Using unchecked arithmetic is safe because the sum of the tranche amounts is equal to the total amount // at this point. uint128 streamedAmount = tranches[0].amount; - uint256 index = 1; - unchecked { - while (tranches[index].timestamp <= currentTime) { - streamedAmount += tranches[index].amount; - index += 1; + for (uint256 i = 1; i < tranches.length; ++i) { + // The loop breaks at the first tranche with a timestamp in the future. A tranche is considered vested if + // its timestamp is less than or equal to the block timestamp. + if (tranches[i].timestamp > blockTimestamp) { + break; + } + unchecked { + streamedAmount += tranches[i].amount; } } @@ -214,27 +217,24 @@ contract SablierV2LockupTranched is //////////////////////////////////////////////////////////////////////////*/ /// @dev See the documentation for the user-facing functions that call this internal function. - function _createWithTimestamps(LockupTranched.CreateWithTimestamps memory params) - internal - returns (uint256 streamId) - { - // Checks: check the broker fee and calculate the amounts. + function _create(LockupTranched.CreateWithTimestamps memory params) internal returns (uint256 streamId) { + // Check: verify the broker fee and calculate the amounts. Lockup.CreateAmounts memory createAmounts = Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); - // Checks: validate the user-provided parameters. - Helpers.checkCreateWithTimestamps(createAmounts.deposit, params.tranches, MAX_TRANCHE_COUNT, params.startTime); + // Check: validate the user-provided parameters. + Helpers.checkCreateLockupTranched(createAmounts.deposit, params.tranches, MAX_TRANCHE_COUNT, params.startTime); - // Load the stream id in a variable. + // Load the stream ID in a variable. streamId = nextStreamId; - // Effects: create the stream. + // Effect: create the stream. Lockup.Stream storage stream = _streams[streamId]; stream.amounts.deposited = createAmounts.deposit; stream.asset = params.asset; stream.isCancelable = params.cancelable; - stream.isTransferable = params.transferable; stream.isStream = true; + stream.isTransferable = params.transferable; stream.sender = params.sender; stream.startTime = params.startTime; @@ -243,24 +243,24 @@ contract SablierV2LockupTranched is uint256 trancheCount = params.tranches.length; stream.endTime = params.tranches[trancheCount - 1].timestamp; - // Effects: store the tranches. Since Solidity lacks a syntax for copying arrays directly from + // Effect: store the tranches. Since Solidity lacks a syntax for copying arrays of structs directly from // memory to storage, a manual approach is necessary. See https://github.com/ethereum/solidity/issues/12783. for (uint256 i = 0; i < trancheCount; ++i) { _tranches[streamId].push(params.tranches[i]); } - // Effects: bump the next stream id. + // Effect: bump the next stream ID. // Using unchecked arithmetic because these calculations cannot realistically overflow, ever. nextStreamId = streamId + 1; } - // Effects: mint the NFT to the recipient. + // Effect: mint the NFT to the recipient. _mint({ to: params.recipient, tokenId: streamId }); - // Interactions: transfer the deposit amount. + // Interaction: transfer the deposit amount. params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit }); - // Interactions: pay the broker fee, if not zero. + // Interaction: pay the broker fee, if not zero. if (createAmounts.brokerFee > 0) { params.asset.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee }); } diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index db7fd5656..abe47289e 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -33,11 +33,11 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { uint128 depositedAmount; string json; ISablierV2Lockup sablier; - string sablierAddress; + string sablierModel; + string sablierStringified; string status; string svg; uint256 streamedPercentage; - string streamingModel; } /// @inheritdoc ISablierV2NFTDescriptor @@ -46,7 +46,8 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { // Load the contracts. vars.sablier = ISablierV2Lockup(address(sablier)); - vars.sablierAddress = address(sablier).toHexString(); + vars.sablierModel = mapSymbol(sablier); + vars.sablierStringified = address(sablier).toHexString(); vars.asset = address(vars.sablier.getAsset(streamId)); vars.assetSymbol = safeAssetSymbol(vars.asset); vars.depositedAmount = vars.sablier.getDepositedAmount(streamId); @@ -57,7 +58,6 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { streamedAmount: vars.sablier.streamedAmountOf(streamId), depositedAmount: vars.depositedAmount }); - vars.streamingModel = mapSymbol(sablier); // Generate the SVG. vars.svg = NFTSVG.generateSVG( @@ -70,11 +70,11 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { startTime: vars.sablier.getStartTime(streamId), endTime: vars.sablier.getEndTime(streamId) }), - sablierAddress: vars.sablierAddress, + sablierAddress: vars.sablierStringified, progress: stringifyPercentage(vars.streamedPercentage), progressNumerical: vars.streamedPercentage, status: vars.status, - streamingModel: vars.streamingModel + sablierModel: vars.sablierModel }) ); @@ -88,15 +88,15 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { }), ',"description":"', generateDescription({ - streamingModel: vars.streamingModel, + sablierModel: vars.sablierModel, assetSymbol: vars.assetSymbol, - sablierAddress: vars.sablierAddress, + sablierStringified: vars.sablierStringified, assetAddress: vars.asset.toHexString(), streamId: streamId.toString(), isTransferable: vars.sablier.isTransferable(streamId) }), '","external_url":"https://sablier.com","name":"', - generateName({ streamingModel: vars.streamingModel, streamId: streamId.toString() }), + generateName({ sablierModel: vars.sablierModel, streamId: streamId.toString() }), '","image":"data:image/svg+xml;base64,', Base64.encode(bytes(vars.svg)), '"}' @@ -194,7 +194,7 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @notice Generates a pseudo-random HSL color by hashing together the `chainid`, the `sablier` address, /// and the `streamId`. This will be used as the accent color for the SVG. function generateAccentColor(address sablier, uint256 streamId) internal view returns (string memory) { - // The chain id is part of the hash so that the generated color is different across chains. + // The chain ID is part of the hash so that the generated color is different across chains. uint256 chainId = block.chainid; // Hash the parameters to generate a pseudo-random bit field, which will be used as entropy. @@ -249,9 +249,9 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @notice Generates a string with the NFT's JSON metadata description, which provides a high-level overview. function generateDescription( - string memory streamingModel, + string memory sablierModel, string memory assetSymbol, - string memory sablierAddress, + string memory sablierStringified, string memory assetAddress, string memory streamId, bool isTransferable @@ -268,15 +268,15 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { return string.concat( "This NFT represents a payment stream in a Sablier V2 ", - streamingModel, + sablierModel, " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", assetSymbol, ".\\n\\n- Stream ID: ", streamId, "\\n- ", - streamingModel, + sablierModel, " Address: ", - sablierAddress, + sablierStringified, "\\n- ", assetSymbol, " Address: ", @@ -288,11 +288,11 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @notice Generates a string with the NFT's JSON metadata name, which is unique for each stream. /// @dev The `streamId` is equivalent to the ERC-721 `tokenId`. - function generateName(string memory streamingModel, string memory streamId) internal pure returns (string memory) { - return string.concat("Sablier V2 ", streamingModel, " #", streamId); + function generateName(string memory sablierModel, string memory streamId) internal pure returns (string memory) { + return string.concat("Sablier V2 ", sablierModel, " #", streamId); } - /// @notice Maps ERC-721 symbols to human-readable streaming models. + /// @notice Maps ERC-721 symbols to human-readable model names. /// @dev Reverts if the symbol is unknown. function mapSymbol(IERC721Metadata sablier) internal view returns (string memory) { string memory symbol = sablier.symbol(); diff --git a/src/abstracts/Adminable.sol b/src/abstracts/Adminable.sol index aac440d29..add9799a0 100644 --- a/src/abstracts/Adminable.sol +++ b/src/abstracts/Adminable.sol @@ -32,7 +32,7 @@ abstract contract Adminable is IAdminable { /// @inheritdoc IAdminable function transferAdmin(address newAdmin) public virtual override onlyAdmin { - // Effects: update the admin. + // Effect: update the admin. admin = newAdmin; // Log the transfer of the admin. diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 526813cd0..6ca1f99de 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -102,7 +102,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function getRecipient(uint256 streamId) external view override returns (address recipient) { - // Checks: the stream NFT exists and return the owner, which is the stream's recipient. + // Check the stream NFT exists and return the owner, which is the stream's recipient. recipient = _requireOwned({ tokenId: streamId }); } @@ -207,7 +207,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ERC721 function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri) { - // Checks: the stream NFT exists. + // Check: the stream NFT exists. _requireOwned({ tokenId: streamId }); // Generate the URI describing the stream NFT. @@ -236,32 +236,32 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function burn(uint256 streamId) external override noDelegateCall notNull(streamId) { - // Checks: only depleted streams can be burned. + // Check: only depleted streams can be burned. if (!_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamNotDepleted(streamId); } - // Checks: + // Check: // 1. NFT exists (see {IERC721.getApproved}). // 2. `msg.sender` is either the owner of the NFT or an approved third party. if (!_isCallerStreamRecipientOrApproved(streamId)) { revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); } - // Effects: burn the NFT. + // Effect: burn the NFT. _burn({ tokenId: streamId }); } /// @inheritdoc ISablierV2Lockup function cancel(uint256 streamId) public override noDelegateCall notNull(streamId) { - // Checks: the stream is neither depleted nor canceled. + // Check: the stream is neither depleted nor canceled. if (_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); } else if (_streams[streamId].wasCanceled) { revert Errors.SablierV2Lockup_StreamCanceled(streamId); } - // Checks: `msg.sender` is the stream's sender. + // Check: `msg.sender` is the stream's sender. if (!_isCallerStreamSender(streamId)) { revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); } @@ -272,7 +272,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function cancelMultiple(uint256[] calldata streamIds) external override noDelegateCall { - // Iterate over the provided array of stream ids and cancel each stream. + // Iterate over the provided array of stream IDs and cancel each stream. uint256 count = streamIds.length; for (uint256 i = 0; i < count; ++i) { // Effects and Interactions: cancel the stream. @@ -282,7 +282,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function renounce(uint256 streamId) external override noDelegateCall notNull(streamId) updateMetadata(streamId) { - // Checks: the stream is not cold. + // Check: the stream is not cold. Lockup.Status status = _statusOf(streamId); if (status == Lockup.Status.DEPLETED) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); @@ -292,7 +292,7 @@ abstract contract SablierV2Lockup is revert Errors.SablierV2Lockup_StreamSettled(streamId); } - // Checks: `msg.sender` is the stream's sender. + // Check: `msg.sender` is the stream's sender. if (!_isCallerStreamSender(streamId)) { revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); } @@ -303,7 +303,7 @@ abstract contract SablierV2Lockup is // Log the renouncement. emit ISablierV2Lockup.RenounceLockupStream(streamId); - // Interactions: if the recipient is a contract, try to invoke the renounce hook on the recipient without + // Interaction: 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) { @@ -313,7 +313,7 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup function setNFTDescriptor(ISablierV2NFTDescriptor newNFTDescriptor) external override onlyAdmin { - // Effects: set the NFT descriptor. + // Effect: set the NFT descriptor. ISablierV2NFTDescriptor oldNftDescriptor = nftDescriptor; nftDescriptor = newNFTDescriptor; @@ -340,17 +340,17 @@ abstract contract SablierV2Lockup is notNull(streamId) updateMetadata(streamId) { - // Checks: the stream is not depleted. + // Check: the stream is not depleted. if (_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); } - // Checks: the withdrawal address is not zero. + // Check: the withdrawal address is not zero. if (to == address(0)) { - revert Errors.SablierV2Lockup_WithdrawToZeroAddress(); + revert Errors.SablierV2Lockup_WithdrawToZeroAddress(streamId); } - // Checks: the withdraw amount is not zero. + // Check: the withdraw amount is not zero. if (amount == 0) { revert Errors.SablierV2Lockup_WithdrawAmountZero(streamId); } @@ -358,13 +358,13 @@ abstract contract SablierV2Lockup is // Retrieve the recipient from storage. address recipient = _ownerOf(streamId); - // Checks: if `msg.sender` is neither the stream's recipient nor an approved third party, the withdrawal address + // Check: if `msg.sender` is neither the stream's recipient nor an approved third party, the withdrawal address // must be the recipient. if (to != recipient && !_isCallerStreamRecipientOrApproved(streamId)) { revert Errors.SablierV2Lockup_WithdrawalAddressNotRecipient(streamId, msg.sender, to); } - // Checks: the withdraw amount is not greater than the withdrawable amount. + // Check: the withdraw amount is not greater than the withdrawable amount. uint128 withdrawableAmount = _withdrawableAmountOf(streamId); if (amount > withdrawableAmount) { revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount); @@ -376,7 +376,7 @@ abstract contract SablierV2Lockup is // 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 + // Interaction: 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) { @@ -388,7 +388,7 @@ abstract contract SablierV2Lockup is }) { } catch { } } - // Interactions: if `msg.sender` is not the sender, the sender is a contract and sender is different from the + // Interaction: if `msg.sender` is not the sender, the sender is a contract and is different from the // recipient, 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 != sender && sender.code.length > 0 && sender != recipient) { @@ -416,7 +416,7 @@ abstract contract SablierV2Lockup is noDelegateCall notNull(streamId) { - // Checks: the caller is the current recipient. This also checks that the NFT was not burned. + // Check: the caller is the current recipient. This also checks that the NFT was not burned. address currentRecipient = _ownerOf(streamId); if (msg.sender != currentRecipient) { revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); @@ -441,14 +441,14 @@ abstract contract SablierV2Lockup is override noDelegateCall { - // Checks: there is an equal number of `streamIds` and `amounts`. + // Check: there is an equal number of `streamIds` and `amounts`. uint256 streamIdsCount = streamIds.length; uint256 amountsCount = amounts.length; if (streamIdsCount != amountsCount) { revert Errors.SablierV2Lockup_WithdrawArrayCountsNotEqual(streamIdsCount, amountsCount); } - // Iterate over the provided array of stream ids and withdraw from each stream. + // Iterate over the provided array of stream IDs, and withdraw from each stream to the recipient. for (uint256 i = 0; i < streamIdsCount; ++i) { // Checks, Effects and Interactions: check the parameters and make the withdrawal. withdraw({ streamId: streamIds[i], to: _ownerOf(streamIds[i]), amount: amounts[i] }); @@ -459,12 +459,12 @@ abstract contract SablierV2Lockup is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Calculates the streamed amount of the stream without looking up the stream's status, which is - /// implemented by child contracts, it can vary depending on the model. + /// @notice Calculates the streamed amount of the stream without looking up the stream's status. + /// @dev This function is implemented by child contracts, so the logic varies depending on the model. function _calculateStreamedAmount(uint256 streamId) internal view virtual returns (uint128); /// @notice Checks whether `msg.sender` is the stream's recipient or an approved third party. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function _isCallerStreamRecipientOrApproved(uint256 streamId) internal view returns (bool) { address recipient = _ownerOf(streamId); return msg.sender == recipient || isApprovedForAll({ owner: recipient, operator: msg.sender }) @@ -472,7 +472,7 @@ abstract contract SablierV2Lockup is } /// @notice Checks whether `msg.sender` is the stream's sender. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function _isCallerStreamSender(uint256 streamId) internal view returns (bool) { return msg.sender == _streams[streamId].sender; } @@ -509,15 +509,15 @@ abstract contract SablierV2Lockup is return _calculateStreamedAmount(streamId); } - /// @notice Overrides the internal ERC-721 `_update` function to check that the stream is transferable and emit - /// an ERC-4906 event. + /// @notice Overrides the {ERC-721._update} function to check that the stream is transferable, and emits an + /// ERC-4906 event. /// @dev There are two cases when the transferable flag is ignored: - /// - If `from` is 0, then the update is a mint and is allowed. + /// - If the current owner is 0, then the update is a mint and is allowed. /// - If `to` is 0, then the update is a burn and is also allowed. /// @param to The address of the new recipient of the stream. - /// @param streamId Id of the stream to update. - /// @param auth Optional parameter. If the value is non 0, the upstream implementation of this function will check - /// that `auth` is either the recipient of the stream, or an approved third party. + /// @param streamId ID of the stream to update. + /// @param auth Optional parameter. If the value is not zero, the overridden implementation will check that + /// `auth` is either the recipient of the stream, or an approved third party. /// @return The original recipient of the `streamId` before the update. function _update( address to, @@ -531,7 +531,7 @@ abstract contract SablierV2Lockup is { address from = _ownerOf(streamId); - if (!_streams[streamId].isTransferable && from != address(0) && to != address(0)) { + if (from != address(0) && to != address(0) && !_streams[streamId].isTransferable) { revert Errors.SablierV2Lockup_NotTransferable(streamId); } @@ -555,12 +555,12 @@ abstract contract SablierV2Lockup is // Retrieve the amounts from storage. Lockup.Amounts memory amounts = _streams[streamId].amounts; - // Checks: the stream is not settled. + // Check: the stream is not settled. if (streamedAmount >= amounts.deposited) { revert Errors.SablierV2Lockup_StreamSettled(streamId); } - // Checks: the stream is cancelable. + // Check: the stream is cancelable. if (!_streams[streamId].isCancelable) { revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); } @@ -569,18 +569,18 @@ abstract contract SablierV2Lockup is uint128 senderAmount = amounts.deposited - streamedAmount; uint128 recipientAmount = streamedAmount - amounts.withdrawn; - // Effects: mark the stream as canceled. + // Effect: mark the stream as canceled. _streams[streamId].wasCanceled = true; - // Effects: make the stream not cancelable anymore, because a stream can only be canceled once. + // Effect: make the stream not cancelable anymore, because a stream can only be canceled once. _streams[streamId].isCancelable = false; - // Effects: If there are no assets left for the recipient to withdraw, mark the stream as depleted. + // Effect: if there are no assets left for the recipient to withdraw, mark the stream as depleted. if (recipientAmount == 0) { _streams[streamId].isDepleted = true; } - // Effects: set the refunded amount. + // Effect: set the refunded amount. _streams[streamId].amounts.refunded = senderAmount; // Retrieve the sender and the recipient from storage. @@ -590,7 +590,7 @@ abstract contract SablierV2Lockup is // Retrieve the ERC-20 asset from storage. IERC20 asset = _streams[streamId].asset; - // Interactions: refund the sender. + // Interaction: refund the sender. asset.safeTransfer({ to: sender, value: senderAmount }); // Log the cancellation. @@ -599,7 +599,7 @@ abstract contract SablierV2Lockup is // 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 + // Interaction: 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 ISablierV2Recipient(recipient).onLockupStreamCanceled({ @@ -613,18 +613,18 @@ abstract contract SablierV2Lockup is /// @dev See the documentation for the user-facing functions that call this internal function. function _renounce(uint256 streamId) internal { - // Checks: the stream is cancelable. + // Check: the stream is cancelable. if (!_streams[streamId].isCancelable) { revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); } - // Effects: renounce the stream by making it not cancelable. + // Effect: renounce the stream by making it not cancelable. _streams[streamId].isCancelable = false; } /// @dev See the documentation for the user-facing functions that call this internal function. function _withdraw(uint256 streamId, address to, uint128 amount) internal { - // Effects: update the withdrawn amount. + // Effect: update the withdrawn amount. _streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount; // Retrieve the amounts from storage. @@ -633,17 +633,17 @@ abstract contract SablierV2Lockup is // Using ">=" instead of "==" for additional safety reasons. In the event of an unforeseen increase in the // withdrawn amount, the stream will still be marked as depleted. if (amounts.withdrawn >= amounts.deposited - amounts.refunded) { - // Effects: mark the stream as depleted. + // Effect: mark the stream as depleted. _streams[streamId].isDepleted = true; - // Effects: make the stream not cancelable anymore, because a depleted stream cannot be canceled. + // Effect: make the stream not cancelable anymore, because a depleted stream cannot be canceled. _streams[streamId].isCancelable = false; } // Retrieve the ERC-20 asset from storage. IERC20 asset = _streams[streamId].asset; - // Interactions: perform the ERC-20 transfer. + // Interaction: perform the ERC-20 transfer. asset.safeTransfer({ to: to, value: amount }); // Log the withdrawal. diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 22419db24..28c00f8ce 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -10,7 +10,7 @@ import { IAdminable } from "./IAdminable.sol"; import { ISablierV2NFTDescriptor } from "./ISablierV2NFTDescriptor.sol"; /// @title ISablierV2Lockup -/// @notice Common logic between all Sablier V2 Lockup streaming contracts. +/// @notice Common logic between all Sablier V2 Lockup contracts. interface ISablierV2Lockup is IAdminable, // 0 inherited components IERC721Metadata // 2 inherited components @@ -20,10 +20,10 @@ interface ISablierV2Lockup is //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when a stream is canceled. - /// @param streamId The id of the stream. + /// @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 asset The contract address of the ERC-20 asset to be distributed. /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's /// decimals. /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the @@ -38,7 +38,7 @@ interface ISablierV2Lockup is ); /// @notice Emitted when a sender gives up the right to cancel a stream. - /// @param streamId The id of the stream. + /// @param streamId The ID of the stream. event RenounceLockupStream(uint256 indexed streamId); /// @notice Emitted when the admin sets a new NFT descriptor contract. @@ -50,9 +50,9 @@ interface ISablierV2Lockup is ); /// @notice Emitted when assets are withdrawn from a stream. - /// @param streamId The id of the 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 asset The contract address of the ERC-20 asset to be distributed. /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount); @@ -60,76 +60,76 @@ interface ISablierV2Lockup is CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the address of the ERC-20 asset used for streaming. + /// @notice Retrieves the address of the ERC-20 asset to be distributed. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getAsset(uint256 streamId) external view returns (IERC20 asset); /// @notice Retrieves the amount deposited in the stream, denoted in units of the asset's decimals. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount); /// @notice Retrieves the stream's end time, which is a Unix timestamp. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getEndTime(uint256 streamId) external view returns (uint40 endTime); /// @notice Retrieves the stream's recipient. /// @dev Reverts if the NFT has been burned. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getRecipient(uint256 streamId) external view returns (address recipient); /// @notice Retrieves the amount refunded to the sender after a cancellation, denoted in units of the asset's /// decimals. This amount is always zero unless the stream was canceled. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getRefundedAmount(uint256 streamId) external view returns (uint128 refundedAmount); /// @notice Retrieves the stream's sender. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getSender(uint256 streamId) external view returns (address sender); /// @notice Retrieves the stream's start time, which is a Unix timestamp. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getStartTime(uint256 streamId) external view returns (uint40 startTime); /// @notice Retrieves the amount withdrawn from the stream, denoted in units of the asset's decimals. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount); /// @notice Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this /// flag is always `false`. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function isCancelable(uint256 streamId) external view returns (bool result); /// @notice Retrieves a flag indicating whether the stream is cold, i.e. settled, canceled, or depleted. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function isCold(uint256 streamId) external view returns (bool result); /// @notice Retrieves a flag indicating whether the stream is depleted. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function isDepleted(uint256 streamId) external view returns (bool result); /// @notice Retrieves a flag indicating whether the stream exists. /// @dev Does not revert if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @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. + /// @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. + /// @param streamId The stream ID for the query. function isWarm(uint256 streamId) external view returns (bool result); /// @notice Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point @@ -137,7 +137,7 @@ interface ISablierV2Lockup is /// @dev This value is hard coded as a constant. function MAX_BROKER_FEE() external view returns (UD60x18); - /// @notice Counter for stream ids, used in the create functions. + /// @notice Counter for stream IDs, used in the create functions. function nextStreamId() external view returns (uint256); /// @notice Contract that generates the non-fungible token URI. @@ -146,11 +146,11 @@ interface ISablierV2Lockup is /// @notice Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units /// of the asset's decimals. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount); /// @notice Retrieves the stream's status. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function statusOf(uint256 streamId) external view returns (Lockup.Status status); /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals. @@ -161,18 +161,18 @@ interface ISablierV2Lockup is /// amount and the refunded amount. Ultimately, when the stream becomes depleted, the streamed amount is equivalent /// to the total amount withdrawn. /// - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount); /// @notice Retrieves a flag indicating whether the stream was canceled. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function wasCanceled(uint256 streamId) external view returns (bool result); /// @notice Calculates the amount that the recipient can withdraw from the stream, denoted in units of the asset's /// decimals. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount); /*////////////////////////////////////////////////////////////////////////// @@ -189,7 +189,7 @@ interface ISablierV2Lockup is /// - The NFT must exist. /// - `msg.sender` must be either the NFT owner or an approved third party. /// - /// @param streamId The id of the stream NFT to burn. + /// @param streamId The ID of the stream NFT to burn. function burn(uint256 streamId) external; /// @notice Cancels the stream and refunds any remaining assets to the sender. @@ -206,7 +206,7 @@ interface ISablierV2Lockup is /// - The stream must be warm and cancelable. /// - `msg.sender` must be the stream's sender. /// - /// @param streamId The id of the stream to cancel. + /// @param streamId The ID of the stream to cancel. function cancel(uint256 streamId) external; /// @notice Cancels multiple streams and refunds any remaining assets to the sender. @@ -219,7 +219,7 @@ interface ISablierV2Lockup is /// Requirements: /// - All requirements from {cancel} must be met for each stream. /// - /// @param streamIds The ids of the streams to cancel. + /// @param streamIds The IDs of the streams to cancel. function cancelMultiple(uint256[] calldata streamIds) external; /// @notice Removes the right of the stream's sender to cancel the stream. @@ -236,7 +236,7 @@ interface ISablierV2Lockup is /// - `msg.sender` must be the stream's sender. /// - The stream must be cancelable. /// - /// @param streamId The id of the stream to renounce. + /// @param streamId The ID of the stream to renounce. function renounce(uint256 streamId) external; /// @notice Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. @@ -267,7 +267,7 @@ interface ISablierV2Lockup is /// - `amount` must be greater than zero and must not exceed the withdrawable amount. /// - `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party. /// - /// @param streamId The id of the stream to withdraw from. + /// @param streamId The ID of the stream to withdraw from. /// @param to The address receiving the withdrawn assets. /// @param amount The amount to withdraw, denoted in units of the asset's decimals. function withdraw(uint256 streamId, address to, uint128 amount) external; @@ -282,7 +282,7 @@ interface ISablierV2Lockup is /// Requirements: /// - Refer to the requirements in {withdraw}. /// - /// @param streamId The id of the stream to withdraw from. + /// @param streamId The ID of the stream to withdraw from. /// @param to The address receiving the withdrawn assets. function withdrawMax(uint256 streamId, address to) external; @@ -300,7 +300,7 @@ interface ISablierV2Lockup is /// - Refer to the requirements in {withdraw}. /// - Refer to the requirements in {IERC721.transferFrom}. /// - /// @param streamId The id of the stream NFT to transfer. + /// @param streamId The ID of the stream NFT to transfer. /// @param newRecipient The address of the new owner of the stream NFT. function withdrawMaxAndTransfer(uint256 streamId, address newRecipient) external; @@ -315,10 +315,10 @@ interface ISablierV2Lockup is /// Requirements: /// - Must not be delegate called. /// - There must be an equal number of `streamIds` and `amounts`. - /// - Each stream id in the array must not reference a null or depleted stream. + /// - Each stream ID in the array must not reference a null or depleted stream. /// - Each amount in the array must be greater than zero and must not exceed the withdrawable amount. /// - /// @param streamIds The ids of the streams to withdraw from. + /// @param streamIds The IDs of the streams to withdraw from. /// @param amounts The amounts to withdraw, denoted in units of the asset's decimals. function withdrawMultiple(uint256[] calldata streamIds, uint128[] calldata amounts) external; } diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index 13f69a2c2..8931d8845 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -7,23 +7,23 @@ import { Lockup, LockupDynamic } from "../types/DataTypes.sol"; import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; /// @title ISablierV2LockupDynamic -/// @notice Creates and manages Lockup streams with dynamic streaming functions. +/// @notice Creates and manages Lockup streams with a dynamic distribution function. interface ISablierV2LockupDynamic is ISablierV2Lockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when a stream is created. - /// @param streamId The id of the newly created stream. + /// @param streamId The ID of the newly created stream. /// @param funder The address which has funded the stream. - /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream. + /// @param sender The address distributing the assets, which will have the ability to cancel the stream. /// @param recipient The address toward which to stream the assets. /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Boolean indicating whether the stream will be cancelable or not. /// @param 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 segments The segments the protocol uses to compose the dynamic distribution function. /// @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. event CreateLockupDynamicStream( @@ -44,19 +44,21 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. + /// @notice Retrieves the stream's range. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return range See the documentation in {DataTypes}. function getRange(uint256 streamId) external view returns (LockupDynamic.Range memory range); - /// @notice Retrieves the segments the protocol uses to compose the custom streaming curve. + /// @notice Retrieves the segments used to compose the dynamic distribution function. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getSegments(uint256 streamId) external view returns (LockupDynamic.Segment[] memory segments); - /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. + /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupDynamic.StreamLD memory stream); /// @notice The maximum number of segments allowed in a stream. @@ -77,7 +79,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithDurations(LockupDynamic.CreateWithDurations calldata params) external returns (uint256 streamId); @@ -95,7 +97,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. - /// - `params.startTime` must be greater than zero and less than the first segment's timestamp + /// - `params.startTime` must be greater than zero and less than the first segment's timestamp. /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`. /// - The segment timestamps must be arranged in ascending order. /// - The last segment timestamp (i.e. the stream's end time) must be in the future. @@ -104,7 +106,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) external returns (uint256 streamId); diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index 63b1a8dc4..11d34e692 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -7,20 +7,20 @@ import { Lockup, LockupLinear } from "../types/DataTypes.sol"; import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; /// @title ISablierV2LockupLinear -/// @notice Creates and manages Lockup streams with linear streaming functions. +/// @notice Creates and manages Lockup streams with a linear distribution function. interface ISablierV2LockupLinear is ISablierV2Lockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when a stream is created. - /// @param streamId The id of the newly created stream. + /// @param streamId The ID of the newly created stream. /// @param funder The address which funded the stream. - /// @param sender The address streaming the assets, with the ability to cancel the stream. + /// @param sender The address distributing the assets, which will have the ability to cancel the stream. /// @param recipient The address receiving the assets. /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Boolean indicating whether the stream will be cancelable or not. /// @param 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 @@ -46,17 +46,19 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @notice Retrieves the stream's cliff time, which is a Unix timestamp. A value of zero means there /// is no cliff. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); - /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. + /// @notice Retrieves the stream's range. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return range See the documentation in {DataTypes}. function getRange(uint256 streamId) external view returns (LockupLinear.Range memory range); - /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. + /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupLinear.StreamLL memory stream); /*////////////////////////////////////////////////////////////////////////// @@ -73,7 +75,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithDurations(LockupLinear.CreateWithDurations calldata params) external returns (uint256 streamId); @@ -98,7 +100,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) external returns (uint256 streamId); diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 526b95ebf..137aefbb4 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -7,23 +7,23 @@ import { Lockup, LockupTranched } from "../types/DataTypes.sol"; import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; /// @title ISablierV2LockupTranched -/// @notice Creates and manages Lockup streams with tranches. +/// @notice Creates and manages Lockup streams with a tranched distribution function. interface ISablierV2LockupTranched is ISablierV2Lockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when a stream is created. - /// @param streamId The id of the newly created stream. + /// @param streamId The ID of the newly created stream. /// @param funder The address which has funded the stream. - /// @param sender The address from which to stream the assets, who will have the ability to cancel the stream. + /// @param sender The address distributing the assets, which will have the ability to cancel the stream. /// @param recipient The address toward which to stream the assets. /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Boolean indicating whether the stream will be cancelable or not. /// @param transferable Boolean indicating whether the stream NFT is transferable or not. - /// @param tranches The tranches the protocol uses to compose the custom streaming curve. + /// @param tranches The tranches the protocol uses to compose the tranched distribution function. /// @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. event CreateLockupTranchedStream( @@ -44,19 +44,21 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the stream's range, which is a struct documented in {DataTypes}. + /// @notice Retrieves the stream's range. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return range See the documentation in {DataTypes}. function getRange(uint256 streamId) external view returns (LockupTranched.Range memory range); - /// @notice Retrieves the stream details, which is a struct documented in {DataTypes}. + /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. + /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupTranched.StreamLT memory stream); - /// @notice Retrieves the tranches the protocol uses to compose the custom distribution curve. + /// @notice Retrieves the tranches used to compose the tranched distribution function. /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream id for the query. + /// @param streamId The stream ID for the query. function getTranches(uint256 streamId) external view returns (LockupTranched.Tranche[] memory tranches); /// @notice The maximum number of tranches allowed in a stream. @@ -77,7 +79,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// - All requirements in {createWithTimestamps} must be met for the calculated parameters. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithDurations(LockupTranched.CreateWithDurations calldata params) external returns (uint256 streamId); @@ -95,7 +97,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. - /// - `params.startTime` must be greater than zero and less than the first tranche's timestamp + /// - `params.startTime` must be greater than zero and less than the first tranche's timestamp. /// - `params.tranches` must have at least one tranche, but not more than `MAX_TRANCHE_COUNT`. /// - The tranche timestamps must be arranged in ascending order. /// - The last tranche timestamp (i.e. the stream's end time) must be in the future. @@ -104,7 +106,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. - /// @return streamId The id of the newly created stream. + /// @return streamId The ID of the newly created stream. function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) external returns (uint256 streamId); diff --git a/src/interfaces/ISablierV2NFTDescriptor.sol b/src/interfaces/ISablierV2NFTDescriptor.sol index f2f757fdf..f0d134cb8 100644 --- a/src/interfaces/ISablierV2NFTDescriptor.sol +++ b/src/interfaces/ISablierV2NFTDescriptor.sol @@ -10,7 +10,7 @@ interface ISablierV2NFTDescriptor { /// @notice Produces the URI describing a particular stream NFT. /// @dev This is a data URI with the JSON contents directly inlined. /// @param sablier The address of the Sablier contract the stream was created in. - /// @param streamId The id of the stream for which to produce a description. + /// @param streamId The ID of the stream for which to produce a description. /// @return uri The URI of the ERC721-compliant metadata. function tokenURI(IERC721Metadata sablier, uint256 streamId) external view returns (string memory uri); } diff --git a/src/interfaces/hooks/ISablierV2Recipient.sol b/src/interfaces/hooks/ISablierV2Recipient.sol index 128d3b958..da95fc046 100644 --- a/src/interfaces/hooks/ISablierV2Recipient.sol +++ b/src/interfaces/hooks/ISablierV2Recipient.sol @@ -4,14 +4,14 @@ pragma solidity >=0.8.22; /// @title ISablierV2Recipient /// @notice Interface for recipient contracts capable of reacting to cancellations, renouncements, and withdrawals. /// @dev Implementation of this interface is optional. If a recipient contract doesn't implement this -/// interface or implements it partially, function execution will not revert. +/// interface or implements it partially, the function execution will not revert. interface ISablierV2Recipient { /// @notice Responds to sender-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 streamId The ID of the canceled stream. /// @param sender The stream's sender, who canceled the stream. /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's /// decimals. @@ -30,7 +30,7 @@ interface ISablierV2Recipient { /// @dev Notes: /// - This function may revert, but the Sablier contract will ignore the revert. /// - /// @param streamId The id of the renounced stream. + /// @param streamId The ID of the renounced stream. function onLockupStreamRenounced(uint256 streamId) external; /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. @@ -38,7 +38,7 @@ interface ISablierV2Recipient { /// @dev Notes: /// - This function may revert, but the Sablier contract will ignore the revert. /// - /// @param streamId The id of the stream being withdrawn from. + /// @param streamId The ID of the stream being withdrawn from. /// @param caller The original `msg.sender` address that triggered the withdrawal. /// @param to The address receiving the withdrawn assets. /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. diff --git a/src/interfaces/hooks/ISablierV2Sender.sol b/src/interfaces/hooks/ISablierV2Sender.sol index 904380460..ab8e576ef 100644 --- a/src/interfaces/hooks/ISablierV2Sender.sol +++ b/src/interfaces/hooks/ISablierV2Sender.sol @@ -4,14 +4,14 @@ pragma solidity >=0.8.22; /// @title ISablierV2Sender /// @notice Interface for sender contracts capable of reacting to withdrawals. /// @dev Implementation of this interface is optional. If a sender contract doesn't implement this -/// interface or implements it partially, function execution will not revert. +/// interface, the function execution will not revert. interface ISablierV2Sender { /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. /// /// @dev Notes: /// - This function may revert, but the Sablier contract will ignore the revert. /// - /// @param streamId The id of the stream being withdrawn from. + /// @param streamId The ID of the stream being withdrawn from. /// @param caller The original `msg.sender` address that triggered the withdrawal. /// @param to The address receiving the withdrawn assets. /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index fc2554f35..a2899d746 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -28,12 +28,12 @@ library Errors { error SablierV2Lockup_DepositAmountZero(); /// @notice Thrown when trying to create a stream with an end time not in the future. - error SablierV2Lockup_EndTimeNotInTheFuture(uint40 currentTime, uint40 endTime); + error SablierV2Lockup_EndTimeNotInTheFuture(uint40 blockTimestamp, uint40 endTime); /// @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. + /// @notice Thrown when the ID references a null stream. error SablierV2Lockup_Null(uint256 streamId); /// @notice Thrown when trying to withdraw an amount greater than the withdrawable amount. @@ -66,12 +66,12 @@ library Errors { /// @notice Thrown when trying to withdraw zero assets from a stream. error SablierV2Lockup_WithdrawAmountZero(uint256 streamId); - /// @notice Thrown when trying to withdraw from multiple streams and the number of stream ids does + /// @notice Thrown when trying to withdraw from multiple streams and the number of stream IDs does /// not match the number of withdraw amounts. error SablierV2Lockup_WithdrawArrayCountsNotEqual(uint256 streamIdsCount, uint256 amountsCount); /// @notice Thrown when trying to withdraw to the zero address. - error SablierV2Lockup_WithdrawToZeroAddress(); + error SablierV2Lockup_WithdrawToZeroAddress(uint256 streamId); /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP-DYNAMIC @@ -107,10 +107,11 @@ library Errors { /// @notice Thrown when trying to create a stream with a cliff time not strictly less than the end time. error SablierV2LockupLinear_CliffTimeNotLessThanEndTime(uint40 cliffTime, uint40 endTime); - /// @notice Thrown when trying to create a stream with a start time greater than the cliff time. + /// @notice Thrown when trying to create a stream with a start time not strictly less than the cliff time, when the + /// cliff time does not have a zero value. error SablierV2LockupLinear_StartTimeNotLessThanCliffTime(uint40 startTime, uint40 cliffTime); - /// @notice Thrown when trying to create a stream with a start time greater than the end time. + /// @notice Thrown when trying to create a stream with a start time not strictly less than the end time. error SablierV2LockupLinear_StartTimeNotLessThanEndTime(uint40 startTime, uint40 endTime); /*////////////////////////////////////////////////////////////////////////// diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index ff64f4ffb..d112ffa3f 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -13,6 +13,68 @@ library Helpers { INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @dev Calculate the timestamps and return the segments. + function calculateSegmentTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) + internal + view + returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) + { + uint256 segmentCount = segments.length; + segmentsWithTimestamps = new LockupDynamic.Segment[](segmentCount); + + // Make the block timestamp the stream's start time. + uint40 startTime = uint40(block.timestamp); + + // It is safe to use unchecked arithmetic because {SablierV2LockupDynamic-_create} will nonetheless check the + // correctness of the calculated segment timestamps. + unchecked { + // The first segment is precomputed because it is needed in the for loop below. + segmentsWithTimestamps[0] = LockupDynamic.Segment({ + amount: segments[0].amount, + exponent: segments[0].exponent, + timestamp: startTime + segments[0].duration + }); + + // Copy the segment amounts and exponents, and calculate the segment timestamps. + for (uint256 i = 1; i < segmentCount; ++i) { + segmentsWithTimestamps[i] = LockupDynamic.Segment({ + amount: segments[i].amount, + exponent: segments[i].exponent, + timestamp: segmentsWithTimestamps[i - 1].timestamp + segments[i].duration + }); + } + } + } + + /// @dev Calculate the timestamps and return the tranches. + function calculateTrancheTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + internal + view + returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) + { + uint256 trancheCount = tranches.length; + tranchesWithTimestamps = new LockupTranched.Tranche[](trancheCount); + + // Make the block timestamp the stream's start time. + uint40 startTime = uint40(block.timestamp); + + // It is safe to use unchecked arithmetic because {SablierV2LockupTranched-_create} will nonetheless check the + // correctness of the calculated tranche timestamps. + unchecked { + // The first tranche is precomputed because it is needed in the for loop below. + tranchesWithTimestamps[0] = + LockupTranched.Tranche({ amount: tranches[0].amount, timestamp: startTime + tranches[0].duration }); + + // Copy the tranche amounts and calculate the tranche timestamps. + for (uint256 i = 1; i < trancheCount; ++i) { + tranchesWithTimestamps[i] = LockupTranched.Tranche({ + amount: tranches[i].amount, + timestamp: tranchesWithTimestamps[i - 1].timestamp + tranches[i].duration + }); + } + } + } + /// @dev Checks the broker fee is not greater than `maxBrokerFee`, and then calculates the broker fee amount and the /// deposit amount from the total amount. function checkAndCalculateBrokerFee( @@ -29,7 +91,7 @@ library Helpers { return Lockup.CreateAmounts(0, 0); } - // Checks: the broker fee is not greater than `maxBrokerFee`. + // Check: the broker fee is not greater than `maxBrokerFee`. if (brokerFee.gt(maxBrokerFee)) { revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee); } @@ -45,8 +107,8 @@ library Helpers { amounts.deposit = totalAmount - amounts.brokerFee; } - /// @dev Checks the parameters of the {SablierV2LockupDynamic-_createWithTimestamps} function. - function checkCreateWithTimestamps( + /// @dev Checks the parameters of the {SablierV2LockupDynamic-_create} function. + function checkCreateLockupDynamic( uint128 depositAmount, LockupDynamic.Segment[] memory segments, uint256 maxSegmentCount, @@ -55,67 +117,70 @@ library Helpers { internal view { - // Checks: the deposit amount is not zero. + // Check: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierV2Lockup_DepositAmountZero(); } - // Checks: the start time is not zero. + // Check: the start time is not zero. if (startTime == 0) { revert Errors.SablierV2Lockup_StartTimeZero(); } - // Checks: the segment count is not zero. + // Check: the segment count is not zero. uint256 segmentCount = segments.length; if (segmentCount == 0) { revert Errors.SablierV2LockupDynamic_SegmentCountZero(); } - // Checks: the segment count is not greater than the maximum allowed. + // Check: the segment count is not greater than the maximum allowed. if (segmentCount > maxSegmentCount) { revert Errors.SablierV2LockupDynamic_SegmentCountTooHigh(segmentCount); } - // Checks: requirements of segments variables. + // Check: requirements of segments. _checkSegments(segments, depositAmount, startTime); } - /// @dev Checks the parameters of the {SablierV2LockupLinear-_createWithTimestamps} function. - function checkCreateWithTimestamps(uint128 depositAmount, LockupLinear.Range memory range) internal view { - // Checks: the deposit amount is not zero. + /// @dev Checks the parameters of the {SablierV2LockupLinear-_create} function. + function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Range memory range) internal view { + // Check: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierV2Lockup_DepositAmountZero(); } - // Checks: the start time is not zero. + // Check: the start time is not zero. if (range.start == 0) { revert Errors.SablierV2Lockup_StartTimeZero(); } - // Checks: the start time is strictly less than the end time. - if (range.start >= range.end) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(range.start, range.end); - } + // Since a cliff time of zero means there is no cliff, the following checks are performed only if it's not zero. + if (range.cliff > 0) { + // Check: the start time is strictly less than the cliff time. + if (range.start >= range.cliff) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(range.start, range.cliff); + } - // Checks: the start time is strictly less than the cliff time when cliff time is not zero. - if (range.cliff > 0 && range.start >= range.cliff) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(range.start, range.cliff); + // Check: the cliff time is strictly less than the end time. + if (range.cliff >= range.end) { + revert Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime(range.cliff, range.end); + } } - // Checks: the cliff time is strictly less than the end time. - if (range.cliff >= range.end) { - revert Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime(range.cliff, range.end); + // Check: the start time is strictly less than the end time. + if (range.start >= range.end) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(range.start, range.end); } - // Checks: the end time is in the future. - uint40 currentTime = uint40(block.timestamp); - if (currentTime >= range.end) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, range.end); + // Check: the end time is in the future. + uint40 blockTimestamp = uint40(block.timestamp); + if (blockTimestamp >= range.end) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, range.end); } } - /// @dev Checks the parameters of the {SablierV2LockupTranched-_createWithTimestamps} function. - function checkCreateWithTimestamps( + /// @dev Checks the parameters of the {SablierV2LockupTranched-_create} function. + function checkCreateLockupTranched( uint128 depositAmount, LockupTranched.Tranche[] memory tranches, uint256 maxTrancheCount, @@ -124,93 +189,31 @@ library Helpers { internal view { - // Checks: the deposit amount is not zero. + // Check: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierV2Lockup_DepositAmountZero(); } - // Checks: the start time is not zero. + // Check: the start time is not zero. if (startTime == 0) { revert Errors.SablierV2Lockup_StartTimeZero(); } - // Checks: the tranche count is not zero. + // Check: the tranche count is not zero. uint256 trancheCount = tranches.length; if (trancheCount == 0) { revert Errors.SablierV2LockupTranched_TrancheCountZero(); } - // Checks: the tranche count is not greater than the maximum allowed. + // Check: the tranche count is not greater than the maximum allowed. if (trancheCount > maxTrancheCount) { revert Errors.SablierV2LockupTranched_TrancheCountTooHigh(trancheCount); } - // Checks: requirements of tranches variables. + // Check: requirements of tranches. _checkTranches(tranches, depositAmount, startTime); } - /// @dev Calculate the timestamps and return the segments. - function calculateSegmentTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) - internal - view - returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) - { - uint256 segmentCount = segments.length; - segmentsWithTimestamps = new LockupDynamic.Segment[](segmentCount); - - // Make the current time the stream's start time. - uint40 startTime = uint40(block.timestamp); - - // It is safe to use unchecked arithmetic because {_createWithTimestamps} will nonetheless check the soundness - // of the calculated segment timestamps. - unchecked { - // Precompute the first segment because of the need to add the start time to the first segment duration. - segmentsWithTimestamps[0] = LockupDynamic.Segment({ - amount: segments[0].amount, - exponent: segments[0].exponent, - timestamp: startTime + segments[0].duration - }); - - // Copy the segment amounts and exponents, and calculate the segment timestamps. - for (uint256 i = 1; i < segmentCount; ++i) { - segmentsWithTimestamps[i] = LockupDynamic.Segment({ - amount: segments[i].amount, - exponent: segments[i].exponent, - timestamp: segmentsWithTimestamps[i - 1].timestamp + segments[i].duration - }); - } - } - } - - /// @dev Calculate the timestamps and return the tranches. - function calculateTrancheTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) - internal - view - returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) - { - uint256 trancheCount = tranches.length; - tranchesWithTimestamps = new LockupTranched.Tranche[](trancheCount); - - // Make the current time the stream's start time. - uint40 startTime = uint40(block.timestamp); - - // It is safe to use unchecked arithmetic because {_createWithTimestamps} will nonetheless check the soundness - // of the calculated tranche timestamps. - unchecked { - // Precompute the first tranche because of the need to add the start time to the first tranche duration. - tranchesWithTimestamps[0] = - LockupTranched.Tranche({ amount: tranches[0].amount, timestamp: startTime + tranches[0].duration }); - - // Copy the tranche amounts and calculate the tranche timestamps. - for (uint256 i = 1; i < trancheCount; ++i) { - tranchesWithTimestamps[i] = LockupTranched.Tranche({ - amount: tranches[i].amount, - timestamp: tranchesWithTimestamps[i - 1].timestamp + tranches[i].duration - }); - } - } - } - /*////////////////////////////////////////////////////////////////////////// PRIVATE CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -229,7 +232,7 @@ library Helpers { private view { - // Checks: the start time is strictly less than the first segment timestamp. + // Check: the start time is strictly less than the first segment timestamp. if (startTime >= segments[0].timestamp) { revert Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( startTime, segments[0].timestamp @@ -238,8 +241,8 @@ library Helpers { // Pre-declare the variables needed in the for loop. uint128 segmentAmountsSum; - uint40 currentTimestamp; - uint40 previousTimestamp; + uint40 currentSegmentTimestamp; + uint40 previousSegmentTimestamp; // Iterate over the segments to: // @@ -250,26 +253,27 @@ library Helpers { // Add the current segment amount to the sum. segmentAmountsSum += segments[index].amount; - // Checks: the current timestamp is strictly greater than the previous timestamp. - currentTimestamp = segments[index].timestamp; - if (currentTimestamp <= previousTimestamp) { + // Check: the current timestamp is strictly greater than the previous timestamp. + currentSegmentTimestamp = segments[index].timestamp; + if (currentSegmentTimestamp <= previousSegmentTimestamp) { revert Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered( - index, previousTimestamp, currentTimestamp + index, previousSegmentTimestamp, currentSegmentTimestamp ); } // Make the current timestamp the previous timestamp of the next loop iteration. - previousTimestamp = currentTimestamp; + previousSegmentTimestamp = currentSegmentTimestamp; } - // Checks: the last timestamp is in the future. - // When the loop exits, the current timestamp is the last timestamp, i.e. the stream's end time. - uint40 currentTime = uint40(block.timestamp); - if (currentTime >= currentTimestamp) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, currentTimestamp); + // Check: the last timestamp is in the future. + // When the loop exits, the current segment's timestamp is the last segment's timestamp, i.e. the stream's end + // time. The variable is not renamed for gas efficiency purposes. + uint40 blockTimestamp = uint40(block.timestamp); + if (blockTimestamp >= currentSegmentTimestamp) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, currentSegmentTimestamp); } - // Checks: the deposit amount is equal to the segment amounts sum. + // Check: the deposit amount is equal to the segment amounts sum. if (depositAmount != segmentAmountsSum) { revert Errors.SablierV2LockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( depositAmount, segmentAmountsSum @@ -291,7 +295,7 @@ library Helpers { private view { - // Checks: the start time is strictly less than the first tranche timestamp. + // Check: the start time is strictly less than the first tranche timestamp. if (startTime >= tranches[0].timestamp) { revert Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( startTime, tranches[0].timestamp @@ -300,8 +304,8 @@ library Helpers { // Pre-declare the variables needed in the for loop. uint128 trancheAmountsSum; - uint40 currentTimestamp; - uint40 previousTimestamp; + uint40 currentTrancheTimestamp; + uint40 previousTrancheTimestamp; // Iterate over the tranches to: // @@ -312,26 +316,27 @@ library Helpers { // Add the current tranche amount to the sum. trancheAmountsSum += tranches[index].amount; - // Checks: the current timestamp is strictly greater than the previous timestamp. - currentTimestamp = tranches[index].timestamp; - if (currentTimestamp <= previousTimestamp) { + // Check: the current timestamp is strictly greater than the previous timestamp. + currentTrancheTimestamp = tranches[index].timestamp; + if (currentTrancheTimestamp <= previousTrancheTimestamp) { revert Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered( - index, previousTimestamp, currentTimestamp + index, previousTrancheTimestamp, currentTrancheTimestamp ); } // Make the current timestamp the previous timestamp of the next loop iteration. - previousTimestamp = currentTimestamp; + previousTrancheTimestamp = currentTrancheTimestamp; } - // Checks: the last timestamp is in the future. - // When the loop exits, the current timestamp is the last timestamp, i.e. the stream's end time. - uint40 currentTime = uint40(block.timestamp); - if (currentTime >= currentTimestamp) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(currentTime, currentTimestamp); + // Check: the last timestamp is in the future. + // When the loop exits, the current tranche's timestamp is the last tranche's timestamp, i.e. the stream's end + // time. The variable is not renamed for gas efficiency purposes. + uint40 blockTimestamp = uint40(block.timestamp); + if (blockTimestamp >= currentTrancheTimestamp) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, currentTrancheTimestamp); } - // Checks: the deposit amount is equal to the tranche amounts sum. + // Check: the deposit amount is equal to the tranche amounts sum. if (depositAmount != trancheAmountsSum) { revert Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum( depositAmount, trancheAmountsSum diff --git a/src/libraries/NFTSVG.sol b/src/libraries/NFTSVG.sol index dedd93cd1..0cfa05c0f 100644 --- a/src/libraries/NFTSVG.sol +++ b/src/libraries/NFTSVG.sol @@ -20,8 +20,8 @@ library NFTSVG { string progress; uint256 progressNumerical; string sablierAddress; + string sablierModel; string status; - string streamingModel; } struct SVGVars { @@ -89,7 +89,7 @@ library NFTSVG { '', SVGElements.BACKGROUND, generateDefs(params.accentColor, params.status, vars.cards), - generateFloatingText(params.sablierAddress, params.streamingModel, params.assetAddress, params.assetSymbol), + generateFloatingText(params.sablierAddress, params.sablierModel, params.assetAddress, params.assetSymbol), generateHrefs(vars.progressXPosition, vars.statusXPosition, vars.amountXPosition, vars.durationXPosition), "" ); @@ -119,7 +119,7 @@ library NFTSVG { function generateFloatingText( string memory sablierAddress, - string memory streamingModel, + string memory sablierModel, string memory assetAddress, string memory assetSymbol ) @@ -131,11 +131,11 @@ library NFTSVG { '', SVGElements.floatingText({ offset: "-100%", - text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", streamingModel) + text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", sablierModel) }), SVGElements.floatingText({ offset: "0%", - text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", streamingModel) + text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", sablierModel) }), SVGElements.floatingText({ offset: "-50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }), SVGElements.floatingText({ offset: "50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }), diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index f7082625f..8bbb378c5 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -66,14 +66,14 @@ library Lockup { DEPLETED } - /// @notice A common data structure to be stored in all child contracts of {SablierV2Lockup}. + /// @notice A common data structure to be stored in all {SablierV2Lockup} models. /// @dev The fields are arranged like this to save gas via tight variable packing. - /// @param sender The address streaming the assets, with the ability to cancel the stream. + /// @param sender The address distributing the assets, with the ability to cancel the stream. /// @param startTime The Unix timestamp indicating the stream's start. /// @param endTime The Unix timestamp indicating the stream's end. /// @param isCancelable Boolean indicating if the stream is cancelable. /// @param wasCanceled Boolean indicating if the stream was canceled. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param isDepleted Boolean indicating if the stream is depleted. /// @param isStream Boolean indicating if the struct entity exists. /// @param isTransferable Boolean indicating if the stream NFT is transferable. @@ -98,17 +98,17 @@ library Lockup { /// @notice Namespace for the structs used in {SablierV2LockupDynamic}. library LockupDynamic { - /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithDurations} function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupDynamic.createWithDurations} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param segments Segments with durations used to compose the custom streaming curve. Timestamps are calculated by - /// starting from `block.timestamp` and adding each duration to the previous timestamp. + /// @param segments Segments with durations used to compose the dynamic distribution function. Timestamps are + /// calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { @@ -122,18 +122,17 @@ library LockupDynamic { Broker broker; } - /// @notice Struct encapsulating the parameters for the {SablierV2LockupDynamic.createWithTimestamps} - /// function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupDynamic.createWithTimestamps} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param startTime The Unix timestamp indicating the stream's start. - /// @param segments Segments used to compose the custom streaming curve. + /// @param segments Segments used to compose the dynamic distribution function. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { @@ -157,9 +156,9 @@ library LockupDynamic { } /// @notice Segment struct used in the Lockup Dynamic stream. - /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals. - /// @param exponent The exponent of this segment, denoted as a fixed-point number. - /// @param timestamp The Unix timestamp indicating this segment's end. + /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. + /// @param exponent The exponent of the segment, denoted as a fixed-point number. + /// @param timestamp The Unix timestamp indicating the segment's end. struct Segment { // slot 0 uint128 amount; @@ -168,18 +167,17 @@ library LockupDynamic { } /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDurations}. - /// @param amount The amount of assets to be streamed in this segment, denoted in units of the asset's decimals. - /// @param exponent The exponent of this segment, denoted as a fixed-point number. - /// @param duration The time difference in seconds between this segment and the previous one. + /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. + /// @param exponent The exponent of the segment, denoted as a fixed-point number. + /// @param duration The time difference in seconds between the segment and the previous one. struct SegmentWithDuration { uint128 amount; UD2x18 exponent; uint40 duration; } - /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within - /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the segments. + /// @notice Struct encapsulating the full details of a stream. + /// @dev Extends `Lockup.Stream` by including the recipient and the segments. struct StreamLD { address sender; address recipient; @@ -198,13 +196,13 @@ library LockupDynamic { /// @notice Namespace for the structs used in {SablierV2LockupLinear}. library LockupLinear { - /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithDurations} function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupLinear.createWithDurations} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param durations Struct containing (i) cliff period duration and (ii) total stream duration, both in seconds. @@ -221,13 +219,13 @@ library LockupLinear { Broker broker; } - /// @notice Struct encapsulating the parameters for the {SablierV2LockupLinear.createWithTimestamps} function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupLinear.createWithTimestamps} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param range Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as Unix @@ -263,9 +261,8 @@ library LockupLinear { uint40 end; } - /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within - /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the cliff value. + /// @notice Struct encapsulating the full details of a stream. + /// @dev Extends `Lockup.Stream` by including the recipient and the cliff time. struct StreamLL { address sender; address recipient; @@ -284,17 +281,17 @@ library LockupLinear { /// @notice Namespace for the structs used in {SablierV2LockupTranched}. library LockupTranched { - /// @notice Struct encapsulating the parameters for the {SablierV2LockupTranched.createWithDurations} function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupTranched.createWithDurations} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param tranches Tranches with durations used to compose the custom streaming curve. Timestamps are calculated by - /// starting from `block.timestamp` and adding each duration to the previous timestamp. + /// @param tranches Tranches with durations used to compose the tranched distribution function. Timestamps are + /// calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { @@ -308,18 +305,17 @@ library LockupTranched { Broker broker; } - /// @notice Struct encapsulating the parameters for the {SablierV2LockupTranched.createWithTimestamps} - /// function. - /// @param sender The address streaming the assets, with the ability to cancel the stream. It doesn't have to be the - /// same as `msg.sender`. + /// @notice Struct encapsulating the parameters of the {SablierV2LockupTranched.createWithTimestamps} function. + /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be + /// the same as `msg.sender`. /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be paid, including the stream deposit and any + /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any /// broker fee, both denoted in units of the asset's decimals. - /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param startTime The Unix timestamp indicating the stream's start. - /// @param tranches Tranches used to compose the custom streaming curve. + /// @param tranches Tranches used to compose the tranched distribution function. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { @@ -342,9 +338,8 @@ library LockupTranched { uint40 end; } - /// @notice Struct encapsulating all the data for a specific id, allowing anyone to retrieve all information within - /// one call to the contract. - /// @dev It contains the same data as the `Lockup.Stream` struct, plus the recipient and the tranches. + /// @notice Struct encapsulating the full details of a stream. + /// @dev Extends `Lockup.Stream` by including the recipient and the tranches. struct StreamLT { address sender; address recipient; @@ -361,8 +356,8 @@ library LockupTranched { } /// @notice Tranche struct used in the Lockup Tranched stream. - /// @param amount The amount of assets to be unlocked in this tranche, denoted in units of the asset's decimals. - /// @param timestamp The Unix timestamp indicating this tranche's end. + /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals. + /// @param timestamp The Unix timestamp indicating the tranche's end. struct Tranche { // slot 0 uint128 amount; @@ -370,8 +365,8 @@ library LockupTranched { } /// @notice Tranche struct used at runtime in {SablierV2LockupTranched.createWithDurations}. - /// @param amount The amount of assets to be unlocked in this tranche, denoted in units of the asset's decimals. - /// @param duration The time difference in seconds between this tranche and the previous one. + /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals. + /// @param duration The time difference in seconds between the tranche and the previous one. struct TrancheWithDuration { uint128 amount; uint40 duration; diff --git a/test/Base.t.sol b/test/Base.t.sol index 7957d2f16..edc907603 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -108,7 +108,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi usdt.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); } - /// @dev Generates a user, labels its address, funds it with test assets and approve the protocol contracts. + /// @dev Generates a user, labels its address, funds it with test assets, and approves the protocol contracts. function createUser(string memory name) internal returns (address payable) { address payable user = payable(makeAddr(name)); vm.deal({ account: user, newBalance: 100 ether }); @@ -126,12 +126,12 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi function deployCoreConditionally() internal { if (!isTestOptimizedProfile()) { nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_COUNT()); + lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(users.admin, nftDescriptor, defaults.MAX_COUNT()); + lockupTranched = new SablierV2LockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); } else { (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = - deployOptimizedCore(users.admin, defaults.MAX_COUNT()); + deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); } vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 2265eaf07..65ee2c540 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -86,7 +86,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { /// /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. - /// - It should bump the next stream id. + /// - It should bump the next stream ID. /// - It should mint the NFT. /// - It should emit a {CreateLockupDynamicStream} event. /// - It may make a withdrawal. @@ -173,7 +173,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { }) ); - // Check if the stream is settled. It is possible for a lockupDynamic stream to settle at the time of creation + // Check if the stream is settled. It is possible for a Lockup Dynamic stream to settle at the time of creation // because some segment amounts can be zero. vars.isSettled = lockupDynamic.refundableAmountOf(vars.streamId) == 0; vars.isCancelable = vars.isSettled ? false : true; @@ -185,8 +185,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { assertEq(actualStream.endTime, vars.range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.segments, params.segments, "segments"); assertEq(actualStream.sender, params.sender, "sender"); @@ -204,7 +204,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { } assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupDynamic.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); @@ -226,7 +226,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { assertEq( vars.actualLockupDynamicBalance, vars.expectedLockupDynamicBalance, - "post-create lockupDynamic contract balance" + "post-create LockupDynamic contract balance" ); // Assert that the holder's balance has been updated. diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index eb5a2e4a4..3bdfb78a8 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -51,11 +51,14 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { uint256 actualRecipientBalance; Lockup.Status actualStatus; uint256[] balances; + uint40 blockTimestamp; + uint40 endTimeLowerBound; uint256 expectedLockupLinearBalance; uint256 expectedHolderBalance; address expectedNFTOwner; uint256 expectedRecipientBalance; Lockup.Status expectedStatus; + bool hasCliff; uint256 initialLockupLinearBalance; uint256 initialRecipientBalance; bool isDepleted; @@ -84,7 +87,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { /// /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. - /// - It should bump the next stream id. + /// - It should bump the next stream ID. /// - It should mint the NFT. /// - It should emit a {MetadataUpdate} event /// - It should emit a {CreateLockupLinearStream} event. @@ -98,31 +101,34 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { /// /// - Multiple values for the sender, recipient, and broker /// - Multiple values for the total amount - /// - Multiple values for the cliff time and the end time - /// - Multiple values for the broker fee, including zero /// - Multiple values for the withdraw amount, including zero /// - Start time in the past /// - Start time in the present /// - Start time in the future - /// - Start time lower than and equal to cliff time + /// - Multiple values for the cliff time and the end time + /// - Cliff time zero and not zero + /// - Multiple values for the broker fee, including zero /// - The whole gamut of stream statuses function testForkFuzz_LockupLinear_CreateWithdrawCancel(Params memory params) external { checkUsers(params.sender, params.recipient, params.broker.account, address(lockupLinear)); // Bound the parameters. - uint40 currentTime = getBlockTimestamp(); + Vars memory vars; + vars.blockTimestamp = getBlockTimestamp(); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.range.start = boundUint40(params.range.start, currentTime - 1000 seconds, currentTime + 10_000 seconds); - params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); + params.range.start = + boundUint40(params.range.start, vars.blockTimestamp - 1000 seconds, vars.blockTimestamp + 10_000 seconds); params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); - // Bound the end time so that it is always greater than both the current time and the cliff time (this is - // a requirement of the protocol). - params.range.end = boundUint40( - params.range.end, - (params.range.cliff <= currentTime ? currentTime : params.range.cliff) + 1, - MAX_UNIX_TIMESTAMP - ); + // The cliff time must be either zero or greater than the start time. + vars.hasCliff = params.range.cliff > 0; + if (vars.hasCliff) { + params.range.cliff = + boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); + } + // Bound the end time so that it is always greater than the block timestamp, the start time, and the cliff time. + vars.endTimeLowerBound = maxOfThree(params.range.start, params.range.cliff, vars.blockTimestamp); + params.range.end = boundUint40(params.range.end, vars.endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Make the holder the caller. resetPrank(HOLDER); @@ -131,8 +137,6 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { CREATE //////////////////////////////////////////////////////////////////////////*/ - Vars memory vars; - // Load the pre-create asset balances. vars.balances = getTokenBalances(address(ASSET), Solarray.addresses(address(lockupLinear), params.broker.account)); @@ -184,8 +188,8 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { assertEq(actualStream.endTime, params.range.end, "endTime"); assertEq(actualStream.isCancelable, true, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.range.start, "startTime"); @@ -193,10 +197,10 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Assert that the stream's status is correct. vars.actualStatus = lockupLinear.statusOf(vars.streamId); - vars.expectedStatus = params.range.start > currentTime ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + vars.expectedStatus = params.range.start > vars.blockTimestamp ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupLinear.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); @@ -230,7 +234,11 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { //////////////////////////////////////////////////////////////////////////*/ // Simulate the passage of time. - params.warpTimestamp = boundUint40(params.warpTimestamp, params.range.cliff, params.range.end + 100 seconds); + params.warpTimestamp = boundUint40( + params.warpTimestamp, + vars.hasCliff ? params.range.cliff : params.range.start + 1 seconds, + params.range.end + 100 seconds + ); vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol index 9bf85d3ff..6ae743529 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/fork/LockupTranched.t.sol @@ -86,7 +86,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { /// /// - It should perform all expected ERC-20 transfers. /// - It should create the stream. - /// - It should bump the next stream id. + /// - It should bump the next stream ID. /// - It should mint the NFT. /// - It should emit a {CreateLockupTranchedStream} event. /// - It may make a withdrawal. @@ -175,7 +175,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { }) ); - // Check if the stream is settled. It is possible for a lockupTranched stream to settle at the time of creation + // Check if the stream is settled. It is possible for a Lockup Tranched stream to settle at the time of creation // because some tranche amounts can be zero. vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; vars.isCancelable = vars.isSettled ? false : true; @@ -187,8 +187,8 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { assertEq(actualStream.endTime, vars.range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.tranches, params.tranches, "tranches"); assertEq(actualStream.sender, params.sender, "sender"); @@ -206,7 +206,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { } assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupTranched.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); @@ -228,7 +228,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { assertEq( vars.actualLockupTranchedBalance, vars.expectedLockupTranchedBalance, - "post-create lockupTranched contract balance" + "post-create LockupTranched contract balance" ); // Assert that the holder's balance has been updated. diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index 41c339147..e08fa8763 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -16,7 +16,7 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In SablierV2LockupDynamic constructedLockupDynamic = new SablierV2LockupDynamic({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor, - maxSegmentCount: defaults.MAX_COUNT() + maxSegmentCount: defaults.MAX_SEGMENT_COUNT() }); // {SablierV2Lockup.constant} @@ -39,7 +39,7 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In // {SablierV2LockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); - uint256 expectedMaxSegmentCount = defaults.MAX_COUNT(); - assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_COUNT"); + uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); + assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_SEGMENT_COUNT"); } } diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 12dc4758b..8d7bbce4f 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -7,7 +7,7 @@ import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic. import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is @@ -126,9 +126,9 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is address funder = users.sender; // Declare the range. - uint40 currentTime = getBlockTimestamp(); + uint40 blockTimestamp = getBlockTimestamp(); LockupDynamic.Range memory range = - LockupDynamic.Range({ start: currentTime, end: currentTime + defaults.TOTAL_DURATION() }); + LockupDynamic.Range({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); // Adjust the segments. LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); @@ -176,7 +176,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupDynamic.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree index 48cdb0c85..9c42b9b8a 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree @@ -15,7 +15,7 @@ createWithDurations.t.sol │ └── it should revert └── when the segment timestamp calculations do not overflow uint256 ├── it should create the stream - ├── it should bump the next stream id + ├── it should bump the next stream ID ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 043e668e3..b8b2e1843 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -11,7 +11,7 @@ import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic. import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup-dynamic/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is @@ -78,7 +78,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenStartTimeNotZero whenSegmentCountNotZero { - uint256 segmentCount = defaults.MAX_COUNT() + 1; + uint256 segmentCount = defaults.MAX_SEGMENT_COUNT() + 1; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) @@ -379,7 +379,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupDynamic.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index 020277763..8105493e3 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -42,14 +42,14 @@ createWithTimestamps.t.sol └── when the asset is a contract ├── when the asset misses the ERC-20 return value │ ├── it should create the stream - │ ├── it should bump the next stream id + │ ├── it should bump the next stream ID │ ├── it should mint the NFT │ ├── it should emit a {MetadataUpdate} event │ ├── it should perform the ERC-20 transfers │ └── it should emit a {CreateLockupDynamicStream} event └── when the asset does not miss the ERC-20 return value ├── it should create the stream - ├── it should bump the next stream id + ├── it should bump the next stream ID ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-dynamic/get-range/getRange.tree b/test/integration/concrete/lockup-dynamic/get-range/getRange.tree index 88dcc9707..61e44d77a 100644 --- a/test/integration/concrete/lockup-dynamic/get-range/getRange.tree +++ b/test/integration/concrete/lockup-dynamic/get-range/getRange.tree @@ -1,5 +1,5 @@ getRange.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct range diff --git a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree b/test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree index b7032eba6..6ac298106 100644 --- a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree +++ b/test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree @@ -1,5 +1,5 @@ getSegments.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct segments diff --git a/test/integration/concrete/lockup-dynamic/get-stream/getStream.tree b/test/integration/concrete/lockup-dynamic/get-stream/getStream.tree index c3278db89..bde21f7b4 100644 --- a/test/integration/concrete/lockup-dynamic/get-stream/getStream.tree +++ b/test/integration/concrete/lockup-dynamic/get-stream/getStream.tree @@ -1,7 +1,7 @@ getStream.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is settled │ └── it should adjust the `isCancelable` flag and return the stream └── given the stream is not settled diff --git a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol index d4b4993b8..4c4e4ad9a 100644 --- a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol @@ -10,7 +10,7 @@ import { Base64 } from "solady/src/utils/Base64.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; /// @dev Requirements for these tests to work: -/// - The stream id must be 1 +/// - The stream ID must be 1 /// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")` /// - The stream asset must have the DAI symbol /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 46263b07e..c6d16323d 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -5,7 +5,7 @@ import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.so import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup-linear/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is @@ -28,6 +28,28 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is expectRevertDueToDelegateCall(success, returnData); } + function test_RevertWhen_CliffDurationCalculationOverflows() external whenNotDelegateCalled { + uint40 startTime = getBlockTimestamp(); + uint40 cliffDuration = MAX_UINT40 - startTime + 2 seconds; + uint40 totalDuration = defaults.TOTAL_DURATION(); + + // Calculate the end time. Needs to be "unchecked" to avoid an overflow. + uint40 cliffTime; + unchecked { + cliffTime = startTime + cliffDuration; + } + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime + ) + ); + + // Create the stream. + createDefaultStreamWithDurations(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); + } + function test_RevertWhen_TotalDurationCalculationOverflows() external whenNotDelegateCalled @@ -66,11 +88,11 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is address funder = users.sender; // Declare the range. - uint40 currentTime = getBlockTimestamp(); + uint40 blockTimestamp = getBlockTimestamp(); LockupLinear.Range memory range = LockupLinear.Range({ - start: currentTime, - cliff: currentTime + defaults.CLIFF_DURATION(), - end: currentTime + defaults.TOTAL_DURATION() + start: blockTimestamp, + cliff: blockTimestamp + defaults.CLIFF_DURATION(), + end: blockTimestamp + defaults.TOTAL_DURATION() }); // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. @@ -112,7 +134,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupLinear.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree index 898296b77..e769f8a06 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree @@ -2,11 +2,14 @@ createWithDurations.t.sol ├── when delegate called │ └── it should revert └── when not delegate called + ├── when the cliff duration calculation overflows uint256 + │ └── it should revert due to the start time being greater than the cliff time + └── when the cliff duration calculation does not overflow uint256 ├── when the total duration calculation overflows uint256 - │ └── it should revert + │ └── it should revert └── when the total duration calculation does not overflow uint256 - ├── it should create the stream - ├── it should bump the next stream id - ├── it should mint the NFT - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupLinearStream} event + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupLinearStream} event diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 16e46c75f..eeb709aeb 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -10,7 +10,7 @@ import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.so import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup-linear/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is @@ -59,11 +59,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithRange(LockupLinear.Range({ start: 0, cliff: cliffTime, end: endTime })); } - modifier whenCliffTimeZero() { - _; - } - - function test_RevertWhen_StartTimeGreaterThanEndTime() + function test_RevertWhen_StartTimeNotLessThanEndTime() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -82,7 +78,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: 0, end: endTime })); } - function test_CreateWithTimestamps_CliffTimeZero() + function test_CreateWithTimestamps_StartTimeLessThanEndTime() external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -100,7 +96,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is expectedStream.cliffTime = 0; assertEq(actualStream, expectedStream); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupLinear.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); @@ -111,10 +107,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } - modifier whenCliffTimeGreaterThanZero() { - _; - } - function test_RevertWhen_StartTimeGreaterThanCliffTime() external whenNotDelegateCalled @@ -122,6 +114,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero + whenStartTimeLessThanEndTime { uint40 startTime = defaults.CLIFF_TIME(); uint40 cliffTime = defaults.START_TIME(); @@ -141,7 +134,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime { uint40 startTime = defaults.START_TIME(); uint40 cliffTime = defaults.END_TIME(); @@ -161,7 +154,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture { @@ -178,7 +171,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture { @@ -196,7 +189,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture whenBrokerFeeNotTooHigh @@ -213,7 +206,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture whenBrokerFeeNotTooHigh @@ -228,7 +221,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeGreaterThanZero - whenStartTimeNotGreaterThanCliffTime + whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture whenBrokerFeeNotTooHigh @@ -290,7 +283,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupLinear.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree index ea808de62..6729ea211 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree @@ -12,15 +12,15 @@ createWithTimestamps.t.sol │ └── it should revert └── when the start time is not zero ├── when the cliff time is zero - │ ├── when the start time is greater than the end time + │ ├── when the start time is not less than the end time │ │ └── it should revert - │ └── when the start time is not greater than the end time + │ └── when the start time is less than the end time │ └── it should create the stream └── when the cliff time is greater than zero ├── when the start time is not less than the cliff time │ └── it should revert - └── when the start time is not greater than the cliff time - ├── when the cliff time is less than the end time + └── when the start time is less than the cliff time + ├── when the cliff time is not less than the end time │ └── it should revert └── when the cliff time is less than the end time ├── when the end time is not in the future @@ -34,16 +34,15 @@ createWithTimestamps.t.sol └── when the asset is a contract ├── when the asset misses the ERC-20 return value │ ├── it should create the stream - │ ├── it should bump the next stream id + │ ├── it should bump the next stream ID │ ├── it should mint the NFT │ ├── it should emit a {MetadataUpdate} event │ ├── it should perform the ERC-20 transfers │ └── it should emit a {CreateLockupLinearStream} event └── when the asset does not miss the ERC-20 return value ├── it should create the stream - ├── it should bump the next stream id + ├── it should bump the next stream ID ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers └── it should emit a {CreateLockupLinearStream} event - diff --git a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree b/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree index afa854032..d588c8587 100644 --- a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree +++ b/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree @@ -1,5 +1,5 @@ getCliffTime.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct cliff time diff --git a/test/integration/concrete/lockup-linear/get-range/getRange.tree b/test/integration/concrete/lockup-linear/get-range/getRange.tree index 88dcc9707..61e44d77a 100644 --- a/test/integration/concrete/lockup-linear/get-range/getRange.tree +++ b/test/integration/concrete/lockup-linear/get-range/getRange.tree @@ -1,5 +1,5 @@ getRange.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct range diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.tree b/test/integration/concrete/lockup-linear/get-stream/getStream.tree index c3278db89..bde21f7b4 100644 --- a/test/integration/concrete/lockup-linear/get-stream/getStream.tree +++ b/test/integration/concrete/lockup-linear/get-stream/getStream.tree @@ -1,7 +1,7 @@ getStream.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is settled │ └── it should adjust the `isCancelable` flag and return the stream └── given the stream is not settled diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol index 30aa29f37..2ce92568e 100644 --- a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol @@ -10,7 +10,7 @@ import { Base64 } from "solady/src/utils/Base64.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; /// @dev Requirements for these tests to work: -/// - The stream id must be 1 +/// - The stream ID must be 1 /// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")` /// - The stream asset must have the DAI symbol /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol index bb7d729e0..ce5481180 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -16,7 +16,7 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ SablierV2LockupTranched constructedLockupTranched = new SablierV2LockupTranched({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor, - maxTrancheCount: defaults.MAX_COUNT() + maxTrancheCount: defaults.MAX_TRANCHE_COUNT() }); // {SablierV2Lockup.constant} @@ -39,7 +39,7 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ // {SablierV2lockupTranched.constructor} uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); - uint256 expectedMaxTrancheCount = defaults.MAX_COUNT(); - assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_COUNT"); + uint256 expectedMaxTrancheCount = defaults.MAX_TRANCHE_COUNT(); + assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_TRANCHE_COUNT"); } } diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 000c2b315..24097a17f 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -5,7 +5,7 @@ import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranche import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup-tranched/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is @@ -120,9 +120,9 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is address funder = users.sender; // Declare the range. - uint40 currentTime = getBlockTimestamp(); + uint40 blockTimestamp = getBlockTimestamp(); LockupTranched.Range memory range = - LockupTranched.Range({ start: currentTime, end: currentTime + defaults.TOTAL_DURATION() }); + LockupTranched.Range({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); LockupTranched.Tranche[] memory tranches = defaults.tranches(); @@ -170,7 +170,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupTranched.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree index b739c2df6..e4b379b65 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree @@ -15,7 +15,7 @@ createWithDurations.t.sol │ └── it should revert └── when the tranche timestamp calculations do not overflow uint256 ├── it should create the stream - ├── it should bump the next stream id + ├── it should bump the next stream ID ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 29a12979a..7519eca56 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -11,8 +11,7 @@ import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranche import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from - "../../../shared/lockup-tranched/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is @@ -79,7 +78,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenStartTimeNotZero whenTrancheCountNotZero { - uint256 trancheCount = defaults.MAX_COUNT() + 1; + uint256 trancheCount = defaults.MAX_TRANCHE_COUNT() + 1; LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) @@ -380,7 +379,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupTranched.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree index 4ffd8d5a5..3c4205768 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -42,14 +42,14 @@ createWithTimestamps.t.sol └── when the asset is a contract ├── when the asset misses the ERC-20 return value │ ├── it should create the stream - │ ├── it should bump the next stream id + │ ├── it should bump the next stream ID │ ├── it should mint the NFT │ ├── it should emit a {MetadataUpdate} event │ ├── it should perform the ERC-20 transfers │ └── it should emit a {CreateLockupTranchedStream} event └── when the asset does not miss the ERC-20 return value ├── it should create the stream - ├── it should bump the next stream id + ├── it should bump the next stream ID ├── it should mint the NFT ├── it should emit a {MetadataUpdate} event ├── it should perform the ERC-20 transfers diff --git a/test/integration/concrete/lockup-tranched/get-range/getRange.tree b/test/integration/concrete/lockup-tranched/get-range/getRange.tree index 88dcc9707..61e44d77a 100644 --- a/test/integration/concrete/lockup-tranched/get-range/getRange.tree +++ b/test/integration/concrete/lockup-tranched/get-range/getRange.tree @@ -1,5 +1,5 @@ getRange.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct range diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.tree b/test/integration/concrete/lockup-tranched/get-stream/getStream.tree index c3278db89..bde21f7b4 100644 --- a/test/integration/concrete/lockup-tranched/get-stream/getStream.tree +++ b/test/integration/concrete/lockup-tranched/get-stream/getStream.tree @@ -1,7 +1,7 @@ getStream.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is settled │ └── it should adjust the `isCancelable` flag and return the stream └── given the stream is not settled diff --git a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree index 826ba60fa..4a8884be1 100644 --- a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree +++ b/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree @@ -1,5 +1,5 @@ getTranches.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct tranches diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol index 28e0257ad..04b8aeb06 100644 --- a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol +++ b/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol @@ -10,7 +10,7 @@ import { Base64 } from "solady/src/utils/Base64.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; /// @dev Requirements for these tests to work: -/// - The stream id must be 1 +/// - The stream ID must be 1 /// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")` /// - The stream asset must have the DAI symbol /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value diff --git a/test/integration/concrete/lockup/burn/burn.tree b/test/integration/concrete/lockup/burn/burn.tree index 90efa59eb..5ec96014b 100644 --- a/test/integration/concrete/lockup/burn/burn.tree +++ b/test/integration/concrete/lockup/burn/burn.tree @@ -2,9 +2,9 @@ burn.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the id references a null stream + ├── given the ID references a null stream │ └── it should revert - └── given the id does not reference a null stream + └── given the ID does not reference a null stream ├── given the stream has not been depleted │ ├── given the stream's status is "PENDING" │ │ └── it should revert diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree index 2cd6a411f..b039e509f 100644 --- a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree +++ b/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree @@ -5,11 +5,11 @@ cancelMultiple.t.sol ├── when the array count is zero │ └── it should do nothing └── when the array count is not zero - ├── given the stream ids array references only null streams + ├── given the stream IDs array references only null streams │ └── it should revert - ├── given the stream ids array references some null streams + ├── given the stream IDs array references some null streams │ └── it should revert - └── given the stream ids array references only streams that are not null + └── given the stream IDs array references only streams that are not null ├── given all streams are cold │ └── it should revert ├── given some streams are cold diff --git a/test/integration/concrete/lockup/cancel/cancel.tree b/test/integration/concrete/lockup/cancel/cancel.tree index 491c3f2e3..52c1ae929 100644 --- a/test/integration/concrete/lockup/cancel/cancel.tree +++ b/test/integration/concrete/lockup/cancel/cancel.tree @@ -2,9 +2,9 @@ cancel.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the id references a null stream + ├── given the ID references a null stream │ └── it should revert - └── given the id does not reference a null stream + └── given the ID does not reference a null stream ├── given the stream is cold │ ├── given the stream's status is "DEPLETED" │ │ └── it should revert @@ -57,4 +57,3 @@ cancel.t.sol ├── it should call the recipient hook ├── it should emit a {MetadataUpdate} event └── it should emit a {CancelLockupStream} event - \ No newline at end of file diff --git a/test/integration/concrete/lockup/get-asset/getAsset.tree b/test/integration/concrete/lockup/get-asset/getAsset.tree index 01bde9485..fd072b636 100644 --- a/test/integration/concrete/lockup/get-asset/getAsset.tree +++ b/test/integration/concrete/lockup/get-asset/getAsset.tree @@ -1,5 +1,5 @@ getAsset.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct address of the asset diff --git a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree b/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree index 5254069e5..7aab0ae56 100644 --- a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree +++ b/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree @@ -1,5 +1,5 @@ getDepositedAmount.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct deposited amount diff --git a/test/integration/concrete/lockup/get-end-time/getEndTime.tree b/test/integration/concrete/lockup/get-end-time/getEndTime.tree index 20359c089..235fe5270 100644 --- a/test/integration/concrete/lockup/get-end-time/getEndTime.tree +++ b/test/integration/concrete/lockup/get-end-time/getEndTime.tree @@ -1,5 +1,5 @@ getEndTime.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct end time diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.tree b/test/integration/concrete/lockup/get-recipient/getRecipient.tree index 5b33ed4a0..075fc23bd 100644 --- a/test/integration/concrete/lockup/get-recipient/getRecipient.tree +++ b/test/integration/concrete/lockup/get-recipient/getRecipient.tree @@ -1,7 +1,7 @@ getRecipient.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the NFT has been burned │ └── it should revert └── given the NFT has not been burned diff --git a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree index 3a8aa8645..0ab67e853 100644 --- a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree +++ b/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree @@ -1,7 +1,7 @@ getRefundedAmount.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream has been canceled │ ├── given the stream's status is "CANCELED" │ │ └── it should return the correct refunded amount diff --git a/test/integration/concrete/lockup/get-sender/getSender.tree b/test/integration/concrete/lockup/get-sender/getSender.tree index 50160b661..65b9b412a 100644 --- a/test/integration/concrete/lockup/get-sender/getSender.tree +++ b/test/integration/concrete/lockup/get-sender/getSender.tree @@ -1,5 +1,5 @@ getSender.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct sender diff --git a/test/integration/concrete/lockup/get-start-time/getStartTime.tree b/test/integration/concrete/lockup/get-start-time/getStartTime.tree index d65e107ab..a0c4f6da7 100644 --- a/test/integration/concrete/lockup/get-start-time/getStartTime.tree +++ b/test/integration/concrete/lockup/get-start-time/getStartTime.tree @@ -1,5 +1,5 @@ getStartTime.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return the correct start time diff --git a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree index 2a88d73c9..ca78cb978 100644 --- a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree +++ b/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree @@ -1,7 +1,7 @@ getWithdrawnAmount.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given there are no previous withdrawals │ └── it should return zero └── given there are previous withdrawals diff --git a/test/integration/concrete/lockup/is-cancelable/isCancelable.tree b/test/integration/concrete/lockup/is-cancelable/isCancelable.tree index 8a36d6dbe..c75cda4f3 100644 --- a/test/integration/concrete/lockup/is-cancelable/isCancelable.tree +++ b/test/integration/concrete/lockup/is-cancelable/isCancelable.tree @@ -1,7 +1,7 @@ isCancelable.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is cold │ └── it should return true └── given the stream is not cold diff --git a/test/integration/concrete/lockup/is-cold/isCold.tree b/test/integration/concrete/lockup/is-cold/isCold.tree index 15bfe3fdc..5902b8b9f 100644 --- a/test/integration/concrete/lockup/is-cold/isCold.tree +++ b/test/integration/concrete/lockup/is-cold/isCold.tree @@ -1,7 +1,7 @@ isCold.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream's status is pending │ └── it should return false ├── given the stream's status is streaming diff --git a/test/integration/concrete/lockup/is-depleted/isDepleted.tree b/test/integration/concrete/lockup/is-depleted/isDepleted.tree index 43149d5aa..3b796bd0c 100644 --- a/test/integration/concrete/lockup/is-depleted/isDepleted.tree +++ b/test/integration/concrete/lockup/is-depleted/isDepleted.tree @@ -1,7 +1,7 @@ isDepleted.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is not depleted │ └── it should return false └── given the stream is depleted diff --git a/test/integration/concrete/lockup/is-stream/isStream.tree b/test/integration/concrete/lockup/is-stream/isStream.tree index 5846352f8..83ae45765 100644 --- a/test/integration/concrete/lockup/is-stream/isStream.tree +++ b/test/integration/concrete/lockup/is-stream/isStream.tree @@ -1,5 +1,5 @@ isStream.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should return false -└── given the id does not reference a null stream +└── given the ID does not reference a null stream └── it should return true diff --git a/test/integration/concrete/lockup/is-transferable/isTransferable.tree b/test/integration/concrete/lockup/is-transferable/isTransferable.tree index 2fefdc265..aba57c19d 100644 --- a/test/integration/concrete/lockup/is-transferable/isTransferable.tree +++ b/test/integration/concrete/lockup/is-transferable/isTransferable.tree @@ -1,7 +1,7 @@ isTransferable.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is not transferable │ └── it should return false └── given the stream is transferable diff --git a/test/integration/concrete/lockup/is-warm/isWarm.tree b/test/integration/concrete/lockup/is-warm/isWarm.tree index be21fe1d1..7044432bb 100644 --- a/test/integration/concrete/lockup/is-warm/isWarm.tree +++ b/test/integration/concrete/lockup/is-warm/isWarm.tree @@ -1,7 +1,7 @@ isWarm.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream's status is pending │ └── it should return true ├── given the stream's status is streaming diff --git a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree index ebfdbcdad..e46acad0d 100644 --- a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree +++ b/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree @@ -1,7 +1,7 @@ refundableAmountOf.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream is not cancelable │ └── it should return zero └── given the stream is cancelable diff --git a/test/integration/concrete/lockup/renounce/renounce.tree b/test/integration/concrete/lockup/renounce/renounce.tree index be03dbc40..1a80ac4d5 100644 --- a/test/integration/concrete/lockup/renounce/renounce.tree +++ b/test/integration/concrete/lockup/renounce/renounce.tree @@ -2,9 +2,9 @@ renounce.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the id references a null stream + ├── given the ID references a null stream │ └── it should revert - └── given the id does not reference a null stream + └── given the ID does not reference a null stream ├── given the stream is cold │ ├── given the stream's status is "DEPLETED" │ │ └── it should revert diff --git a/test/integration/concrete/lockup/status-of/statusOf.tree b/test/integration/concrete/lockup/status-of/statusOf.tree index 6d0bfda29..03c12a2ef 100644 --- a/test/integration/concrete/lockup/status-of/statusOf.tree +++ b/test/integration/concrete/lockup/status-of/statusOf.tree @@ -1,7 +1,7 @@ statusOf.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given assets have been fully withdrawn │ └── it should return DEPLETED └── given assets have not been fully withdrawn diff --git a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree index dbc0970ab..f0784e8ea 100644 --- a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree +++ b/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree @@ -1,7 +1,7 @@ streamedAmountOf.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream has been canceled │ ├── given the stream's status is "CANCELED" │ │ └── it should return the correct streamed amount diff --git a/test/integration/concrete/lockup/was-canceled/wasCanceled.tree b/test/integration/concrete/lockup/was-canceled/wasCanceled.tree index 5dd4e1e3a..0be9ecbda 100644 --- a/test/integration/concrete/lockup/was-canceled/wasCanceled.tree +++ b/test/integration/concrete/lockup/was-canceled/wasCanceled.tree @@ -1,7 +1,7 @@ wasCanceled.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream was not canceled │ └── it should return false └── given the stream was canceled diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol index 6261abcbf..55268ccaf 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -1,5 +1,4 @@ // SPDX-License-Identifier: UNLICENSED -// solhint-disable max-line-length pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; @@ -9,8 +8,11 @@ import { Integration_Test } from "../../../Integration.t.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, Withdraw_Integration_Shared_Test { + uint128 internal withdrawAmount; + function setUp() public virtual override(Integration_Test, Withdraw_Integration_Shared_Test) { Withdraw_Integration_Shared_Test.setUp(); + withdrawAmount = defaults.WITHDRAW_AMOUNT(); } modifier givenDifferentSenderAndRecipient() { @@ -25,7 +27,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W { address unknownCaller = address(0xCAFE); - // Create the stream with sender and recipient as contracts. + // Create the stream with both the sender and the recipient as contracts. uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make `unknownCaller` the caller in this test. @@ -34,16 +36,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the recipient hook. vm.expectCall({ callee: address(goodRecipient), data: abi.encodeCall( ISablierV2Recipient.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); @@ -52,7 +51,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); @@ -66,7 +65,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W givenRecipientContract givenDifferentSenderAndRecipient { - // Create the stream with sender and recipient as contracts. + // Create the stream with both the sender and the recipient as contracts. uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Approve the operator to handle the stream. @@ -79,16 +78,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the recipient hook. vm.expectCall({ callee: address(goodRecipient), data: abi.encodeCall( ISablierV2Recipient.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); @@ -97,7 +93,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); @@ -111,7 +107,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W givenRecipientContract givenDifferentSenderAndRecipient { - // Create the stream with sender and recipient as contracts. + // Create the stream with both the sender and the recipient as contracts. uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make the sender the caller in this test. @@ -120,26 +116,23 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect 1 call to the recipient hook. vm.expectCall({ callee: address(goodRecipient), data: abi.encodeCall( ISablierV2Recipient.onLockupStreamWithdrawn, (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); - // Expect 0 calls to the sender hook. + // Expect no calls to the sender hook. vm.expectCall({ callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), + ), count: 0 }); @@ -153,7 +146,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W givenRecipientContract givenDifferentSenderAndRecipient { - // Create the stream with sender and recipient as contracts. + // Create the stream with both the sender and the recipient as contracts. uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make the recipient the caller in this test. @@ -162,16 +155,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect 0 calls to the recipient hook. + // Expect no calls to the recipient hook. vm.expectCall({ callee: address(goodRecipient), data: abi.encodeCall( ISablierV2Recipient.onLockupStreamWithdrawn, (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) - ), + ), count: 0 }); @@ -181,7 +171,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) - ), + ), count: 1 }); @@ -196,8 +186,8 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W function test_WithdrawHooks_SenderHook_CallerUnknown() external givenSenderContract givenSameSenderAndRecipient { address unknownCaller = address(0xCAFE); - // Create the stream with recipient which is same as the sender contract. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); + // Create the stream with the recipient as the sender. + uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Make unknownCaller the caller in this test. changePrank({ msgSender: unknownCaller }); @@ -205,15 +195,12 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the sender hook. vm.expectCall({ callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodSender), withdrawAmount) - ), + ), count: 1 }); @@ -227,7 +214,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W givenSameSenderAndRecipient { // Create the stream with recipient which is same as the sender contract. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); + uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Approve the operator to handle the stream. changePrank({ msgSender: address(goodSender) }); @@ -239,15 +226,12 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the sender hook. vm.expectCall({ callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodSender), withdrawAmount) - ), + ), count: 1 }); @@ -257,7 +241,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W function test_WithdrawHooks_SenderHook_CallerSender() external givenSenderContract givenSameSenderAndRecipient { // Create the stream with the sender as the recipient. - uint256 streamId = createDefaultStreamToSender(address(goodSender)); + uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Approve the operator to handle the stream. changePrank({ msgSender: address(goodSender) }); @@ -265,16 +249,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect 0 calls to the sender hook. + // Expect no calls to the sender hook. vm.expectCall({ callee: address(goodSender), data: abi.encodeCall( ISablierV2Sender.onLockupStreamWithdrawn, (streamId, address(goodSender), address(goodSender), withdrawAmount) - ), + ), count: 0 }); diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree index 79a896aa2..f0500c61a 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree @@ -12,7 +12,7 @@ withdrawHooks.t.sol │ └── when the caller is the recipient │ ├── it should make one hook call to the sender │ └── it should not make any hook call to the recipient -└── given the recipient is same as the sender +└── given the recipient is the same as the sender ├── when the caller is unknown │ └── it should make one hook call to the sender ├── when the caller is an approved third party diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree index f53682e9e..cb45e2a6e 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree @@ -2,9 +2,9 @@ withdrawMaxAndTransfer.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the id references a null stream + ├── given the ID references a null stream │ └── it should revert - └── given the id does not reference a null stream + └── given the ID does not reference a null stream ├── given the stream is not transferable │ └── it should revert └── given the stream is transferable diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree index 6759b6aa2..c9fbb0d35 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree +++ b/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree @@ -8,11 +8,11 @@ withdrawMultiple.t.sol ├── when the array counts are zero │ └── it should do nothing └── when the array counts are not zero - ├── given the stream ids array references only null streams + ├── given the stream IDs array references only null streams │ └── it should revert - ├── given the stream ids array references some null streams + ├── given the stream IDs array references some null streams │ └── it should revert - └── given the stream ids array references only non-null streams + └── given the stream IDs array references only non-null streams ├── given all streams' statuses are "DEPLETED" │ └── it should revert ├── given some streams' statuses are "DEPLETED" diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index 55d0d05c8..e7a72167e 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -46,7 +46,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_RevertWhen_ToZeroAddress() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: address(0), amount: withdrawAmount }); } diff --git a/test/integration/concrete/lockup/withdraw/withdraw.tree b/test/integration/concrete/lockup/withdraw/withdraw.tree index fccd07685..8cf51bdf3 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.tree +++ b/test/integration/concrete/lockup/withdraw/withdraw.tree @@ -2,9 +2,9 @@ withdraw.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the id references a null stream + ├── given the ID references a null stream │ └── it should revert - └── given the id does not reference a null stream + └── given the ID does not reference a null stream ├── given the stream's status is "DEPLETED" │ └── it should revert └── given the stream's status is not "DEPLETED" diff --git a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree index 27c4896ef..183bddf1b 100644 --- a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree +++ b/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree @@ -1,7 +1,7 @@ withdrawableAmountOf.t.sol -├── given the id references a null stream +├── given the ID references a null stream │ └── it should revert -└── given the id does not reference a null stream +└── given the ID does not reference a null stream ├── given the stream has been canceled │ ├── given the stream's status is "CANCELED" │ │ └── it should return the correct withdrawable amount diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 4d7e7e2e2..07461069b 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ERC721Mock } from "../../../../mocks/erc721/ERC721Mock.sol"; +import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import { MockERC721 } from "forge-std/src/mocks/MockERC721.sol"; import { Errors } from "src/libraries/Errors.sol"; @@ -9,9 +10,10 @@ import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol" contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { function test_RevertGiven_UnknownNFT() external { - ERC721Mock nft = new ERC721Mock("Foo NFT", "FOO"); + MockERC721 nft = new MockERC721(); + nft.initialize("Foo", "FOO"); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2NFTDescriptor_UnknownNFT.selector, nft, "FOO")); - nftDescriptorMock.mapSymbol_(nft); + nftDescriptorMock.mapSymbol_(IERC721Metadata(address(nft))); } modifier givenKnownNFT() { @@ -19,14 +21,20 @@ contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concre } function test_MapSymbol_LockupDynamic() external view givenKnownNFT { - string memory actualStreamingModel = nftDescriptorMock.mapSymbol_(lockupDynamic); - string memory expectedStreamingModel = "Lockup Dynamic"; - assertEq(actualStreamingModel, expectedStreamingModel, "streamingModel"); + string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupDynamic); + string memory expectedSablierModel = "Lockup Dynamic"; + assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); } function test_MapSymbol_LockupLinear() external view givenKnownNFT { - string memory actualStreamingModel = nftDescriptorMock.mapSymbol_(lockupLinear); - string memory expectedStreamingModel = "Lockup Linear"; - assertEq(actualStreamingModel, expectedStreamingModel, "streamingModel"); + string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupLinear); + string memory expectedSablierModel = "Lockup Linear"; + assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); + } + + function test_MapSymbol_LockupTranched() external view givenKnownNFT { + string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupTranched); + string memory expectedSablierModel = "Lockup Tranched"; + assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); } } diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 7cd7869d1..49dee2114 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is @@ -105,9 +105,9 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, users.recipient, "recipient"); assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); @@ -119,7 +119,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is vars.expectedStatus = vars.isSettled ? Lockup.Status.SETTLED : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupDynamic.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 22a98f8d2..bbedfef03 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -7,7 +7,7 @@ import { stdError } from "forge-std/src/StdError.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-dynamic/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is @@ -30,7 +30,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenDepositAmountNotZero whenSegmentCountNotZero { - segmentCount = _bound(segmentCount, defaults.MAX_COUNT() + 1 seconds, defaults.MAX_COUNT() * 10); + uint256 defaultMax = defaults.MAX_SEGMENT_COUNT(); + segmentCount = _bound(segmentCount, defaultMax + 1, defaultMax * 10); LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) @@ -267,9 +268,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.segments, params.segments, "segments"); @@ -287,7 +288,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is } assertEq(vars.actualStatus, vars.expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupDynamic.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 4ea56540c..0e1cc38ee 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -57,12 +57,12 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForOneSegment(currentTime, segment); + uint128 expectedStreamedAmount = calculateStreamedAmountForOneSegment(blockTimestamp, segment); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -118,12 +118,13 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForMultipleSegments(currentTime, segments, totalAmount); + uint128 expectedStreamedAmount = + calculateStreamedAmountForMultipleSegments(blockTimestamp, segments, totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 045ebc2c5..27751e524 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -45,13 +45,13 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = - calculateStreamedAmountForMultipleSegments(currentTime, defaults.segments(), defaults.DEPOSIT_AMOUNT()); + calculateStreamedAmountForMultipleSegments(blockTimestamp, defaults.segments(), defaults.DEPOSIT_AMOUNT()); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -79,12 +79,12 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is { timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); - // Define the current time. - uint40 currentTime = defaults.START_TIME() + timeJump; + // Define the block timestamp. + uint40 blockTimestamp = defaults.START_TIME() + timeJump; // Bound the withdraw amount. uint128 streamedAmount = - calculateStreamedAmountForMultipleSegments(currentTime, defaults.segments(), defaults.DEPOSIT_AMOUNT()); + calculateStreamedAmountForMultipleSegments(blockTimestamp, defaults.segments(), defaults.DEPOSIT_AMOUNT()); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with @@ -95,7 +95,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ newTimestamp: currentTime }); + vm.warp({ newTimestamp: blockTimestamp }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index 9e69b82af..50c78efef 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup-linear/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is @@ -26,7 +26,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is whenCliffDurationCalculationDoesNotOverflow { uint40 startTime = getBlockTimestamp(); - durations.cliff = boundUint40(durations.cliff, 0, MAX_UINT40 - startTime); + durations.cliff = boundUint40(durations.cliff, 1 seconds, MAX_UINT40 - startTime); durations.total = boundUint40(durations.total, MAX_UINT40 - startTime + 1 seconds, MAX_UINT40); // Calculate the cliff time and the end time. Needs to be "unchecked" to allow an overflow. @@ -40,7 +40,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime + Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime ) ); @@ -54,7 +54,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is whenCliffDurationCalculationDoesNotOverflow whenTotalDurationCalculationDoesNotOverflow { - durations.total = boundUint40(durations.total, 1, MAX_UNIX_TIMESTAMP); + durations.total = boundUint40(durations.total, 1 seconds, MAX_UNIX_TIMESTAMP); vm.assume(durations.cliff < durations.total); // Make the Sender the stream's funder (recall that the Sender is the default caller). @@ -104,7 +104,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. uint256 actualNextStreamId = lockupLinear.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 09ad044fa..444a0e7e9 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -6,7 +6,7 @@ import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-linear/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is @@ -22,7 +22,21 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is CreateWithTimestamps_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_StartTimeGreaterThanCliffTime(uint40 startTime) + function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) + external + whenNotDelegateCalled + whenRecipientNonZeroAddress + whenDepositAmountNotZero + { + vm.assume(broker.account != address(0)); + broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + ); + createDefaultStreamWithBroker(broker); + } + + function testFuzz_RevertWhen_StartTimeNotLessThanCliffTime(uint40 startTime) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -45,10 +59,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenNotDelegateCalled whenRecipientNonZeroAddress whenDepositAmountNotZero - whenStartTimeNotGreaterThanCliffTime { uint40 startTime = defaults.START_TIME(); - endTime = boundUint40(endTime, startTime + 1, startTime + 2 weeks); + endTime = boundUint40(endTime, startTime + 1 seconds, startTime + 2 weeks); cliffTime = boundUint40(cliffTime, endTime, MAX_UNIX_TIMESTAMP); vm.expectRevert( @@ -59,23 +72,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenStartTimeNotGreaterThanCliffTime - whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture - { - vm.assume(broker.account != address(0)); - broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) - ); - createDefaultStreamWithBroker(broker); - } - struct Vars { uint256 actualNextStreamId; address actualNFTOwner; @@ -95,6 +91,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is /// - Start time in the present /// - Start time in the future /// - Start time lower than and equal to cliff time + /// - Cliff time zero and not zero /// - Multiple values for the cliff time and the end time /// - Multiple values for the broker fee, including zero function testFuzz_CreateWithTimestamps( @@ -105,7 +102,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenNotDelegateCalled whenDepositAmountNotZero whenStartTimeNotZero - whenStartTimeNotGreaterThanCliffTime whenCliffTimeLessThanEndTime whenEndTimeInTheFuture whenBrokerFeeNotTooHigh @@ -116,11 +112,18 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vm.assume(params.totalAmount != 0); params.range.start = boundUint40(params.range.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); - params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); - params.range.end = boundUint40(params.range.end, params.range.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.transferable = true; + // The cliff time must be either zero or greater than the start time. + if (params.range.cliff > 0) { + params.range.cliff = + boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); + params.range.end = boundUint40(params.range.end, params.range.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); + } else { + params.range.end = boundUint40(params.range.end, params.range.start + 1 seconds, MAX_UNIX_TIMESTAMP); + } + // Calculate the fee amounts and the deposit amount. Vars memory vars; @@ -181,8 +184,8 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is assertEq(actualStream.endTime, params.range.end, "endTime"); assertEq(actualStream.isCancelable, params.cancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.startTime, params.range.start, "startTime"); @@ -193,7 +196,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vars.expectedStatus = params.range.start > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupLinear.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index c8f452713..4f7abddc9 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -70,12 +70,12 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmount(currentTime, depositAmount); + uint128 expectedStreamedAmount = calculateStreamedAmount(blockTimestamp, depositAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index bdd34946c..7bb8d459b 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -67,12 +67,12 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); - uint128 expectedWithdrawableAmount = calculateStreamedAmount(currentTime, depositAmount); + uint128 expectedWithdrawableAmount = calculateStreamedAmount(blockTimestamp, depositAmount); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -105,11 +105,11 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); depositAmount = boundUint128(depositAmount, 10_000, MAX_UINT128); - // Define the current time. - uint40 currentTime = defaults.START_TIME() + timeJump; + // Define the block timestamp. + uint40 blockTimestamp = defaults.START_TIME() + timeJump; // Bound the withdraw amount. - uint128 streamedAmount = calculateStreamedAmount(currentTime, depositAmount); + uint128 streamedAmount = calculateStreamedAmount(blockTimestamp, depositAmount); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Mint enough assets to the Sender. @@ -122,7 +122,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ newTimestamp: currentTime }); + vm.warp({ newTimestamp: blockTimestamp }); // Make the withdrawal. lockupLinear.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 6a1468668..2a50e7a21 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; -import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup-tranched/createWithDurations.t.sol"; +import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is @@ -105,9 +105,9 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.tranches, vars.tranchesWithTimestamps, "tranches"); assertEq(actualStream.sender, users.sender, "sender"); @@ -119,7 +119,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is vars.expectedStatus = vars.isSettled ? Lockup.Status.SETTLED : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupTranched.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 251bbf1e7..a81214e25 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -7,7 +7,7 @@ import { stdError } from "forge-std/src/StdError.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; -import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup-tranched/createWithTimestamps.t.sol"; +import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is @@ -30,7 +30,8 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenDepositAmountNotZero whenTrancheCountNotZero { - trancheCount = _bound(trancheCount, defaults.MAX_COUNT() + 1 seconds, defaults.MAX_COUNT() * 10); + uint256 defaultMax = defaults.MAX_TRANCHE_COUNT(); + trancheCount = _bound(trancheCount, defaultMax + 1, defaultMax * 10); LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) @@ -270,9 +271,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.asset, dai, "asset"); assertEq(actualStream.endTime, range.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); + assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.tranches, params.tranches, "tranches"); @@ -290,7 +291,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is } assertEq(vars.actualStatus, vars.expectedStatus); - // Assert that the next stream id has been bumped. + // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockupTranched.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); diff --git a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 35ab45655..29c105b53 100644 --- a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -74,12 +74,12 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is uint256 streamId = lockupTranched.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(currentTime, tranches, totalAmount); + uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(blockTimestamp, tranches, totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 35d86f64c..407414ba6 100644 --- a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -45,13 +45,13 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is uint256 streamId = lockupTranched.createWithTimestamps(params); // Simulate the passage of time. - uint40 currentTime = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: currentTime }); + uint40 blockTimestamp = defaults.START_TIME() + timeJump; + vm.warp({ newTimestamp: blockTimestamp }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = - calculateStreamedAmountForTranches(currentTime, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + calculateStreamedAmountForTranches(blockTimestamp, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -79,12 +79,12 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is { timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); - // Define the current time. - uint40 currentTime = defaults.START_TIME() + timeJump; + // Define the block timestamp. + uint40 blockTimestamp = defaults.START_TIME() + timeJump; // Bound the withdraw amount. uint128 streamedAmount = - calculateStreamedAmountForTranches(currentTime, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + calculateStreamedAmountForTranches(blockTimestamp, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with @@ -95,7 +95,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is uint256 streamId = lockupTranched.createWithTimestamps(params); // Simulate the passage of time. - vm.warp({ newTimestamp: currentTime }); + vm.warp({ newTimestamp: blockTimestamp }); // Make the withdrawal. lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/integration/fuzz/lockup/cancel.t.sol index c4188c082..3597ba4bb 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/integration/fuzz/lockup/cancel.t.sol @@ -39,7 +39,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// - /// - Multiple values for the current time + /// - Multiple values for the block timestamp /// - With and without withdrawals function testFuzz_Cancel( uint256 timeJump, diff --git a/test/integration/fuzz/lockup/cancelMultiple.t.sol b/test/integration/fuzz/lockup/cancelMultiple.t.sol index aac5f1d6c..eac94ed5c 100644 --- a/test/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/integration/fuzz/lockup/cancelMultiple.t.sol @@ -33,7 +33,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - // Create the stream ids array. + // Create the stream IDs array. uint256[] memory streamIds = Solarray.uint256s(testStreamIds[0], streamId); // Expect the assets to be refunded to the Sender. diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/integration/fuzz/lockup/withdraw.t.sol index fd4dbecd9..a5b6d5618 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/integration/fuzz/lockup/withdraw.t.sol @@ -83,7 +83,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// - /// - Multiple values for the current time. + /// - Multiple values for the block timestamp. /// - Multiple values for the withdrawal address. /// - Multiple withdraw amounts. function testFuzz_Withdraw_StreamHasBeenCanceled( diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 08ee66844..f5809e894 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -47,19 +47,19 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh } } - /// @dev Creates the default stream. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStream() internal override returns (uint256 streamId) { streamId = lockupDynamic.createWithTimestamps(_params.createWithTimestamps); } - /// @dev Creates the default stream with the provided asset. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.asset = asset; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided broker. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.broker = broker; @@ -81,21 +81,21 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithDurations(params); } - /// @dev Creates the default stream with the provided end time. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.segments[1].timestamp = endTime; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates a stream that will not be cancelable. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.cancelable = false; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the NFT transfer disabled. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.transferable = false; @@ -110,7 +110,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.recipient = recipient; @@ -127,28 +127,28 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.sender = sender; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided start time.. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.startTime = startTime; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided total amount. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; params.totalAmount = totalAmount; streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender and recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithUsers( address recipient, address sender @@ -158,8 +158,8 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; params.recipient = recipient; + params.sender = sender; streamId = lockupDynamic.createWithTimestamps(params); } } diff --git a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol deleted file mode 100644 index b9a7a5fd2..000000000 --- a/test/integration/shared/lockup-dynamic/createWithTimestamps.t.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; - -contract CreateWithTimestamps_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - streamId = lockupDynamic.nextStreamId(); - } - - modifier whenNotDelegateCalled() { - _; - } - - modifier whenRecipientNonZeroAddress() { - _; - } - - modifier whenDepositAmountNotZero() { - _; - } - - modifier whenStartTimeNotZero() { - _; - } - - modifier whenSegmentCountNotZero() { - _; - } - - modifier whenSegmentCountNotTooHigh() { - _; - } - - modifier whenSegmentAmountsSumDoesNotOverflow() { - _; - } - - modifier whenStartTimeLessThanFirstSegmentTimestamp() { - _; - } - - modifier whenSegmentTimestampsOrdered() { - _; - } - - modifier whenEndTimeInTheFuture() { - _; - } - - modifier whenDepositAmountEqualToSegmentAmountsSum() { - _; - } - - modifier whenBrokerFeeNotTooHigh() { - _; - } - - modifier whenAssetContract() { - _; - } - - modifier whenAssetERC20() { - _; - } -} diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index eed455052..0dd6b92ee 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -24,19 +24,19 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha _params.createWithTimestamps = defaults.createWithTimestampsLL(); } - /// @dev Creates the default stream. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStream() internal override returns (uint256 streamId) { streamId = lockupLinear.createWithTimestamps(_params.createWithTimestamps); } - /// @dev Creates the default stream with the provided address. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.asset = asset; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided broker. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.broker = broker; @@ -58,21 +58,21 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha streamId = lockupLinear.createWithDurations(params); } - /// @dev Creates the default stream that is not cancelable. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.cancelable = false; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the NFT transfer disabled. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.transferable = false; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided end time. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.range.end = endTime; @@ -86,35 +86,35 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.recipient = recipient; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.sender = sender; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided start time. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.range.start = startTime; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided total amount. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; params.totalAmount = totalAmount; streamId = lockupLinear.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender and recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithUsers( address recipient, address sender @@ -124,8 +124,8 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; params.recipient = recipient; + params.sender = sender; streamId = lockupLinear.createWithTimestamps(params); } } diff --git a/test/integration/shared/lockup-linear/createWithDurations.t.sol b/test/integration/shared/lockup-linear/createWithDurations.t.sol deleted file mode 100644 index f851e18e1..000000000 --- a/test/integration/shared/lockup-linear/createWithDurations.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; - -contract CreateWithDurations_Integration_Shared_Test is LockupLinear_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - streamId = lockupLinear.nextStreamId(); - } - - modifier whenNotDelegateCalled() { - _; - } - - modifier whenCliffDurationCalculationDoesNotOverflow() { - _; - } - - modifier whenTotalDurationCalculationDoesNotOverflow() { - _; - } -} diff --git a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol b/test/integration/shared/lockup-linear/createWithTimestamps.t.sol deleted file mode 100644 index 09975a86c..000000000 --- a/test/integration/shared/lockup-linear/createWithTimestamps.t.sol +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; - -abstract contract CreateWithTimestamps_Integration_Shared_Test is LockupLinear_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - streamId = lockupLinear.nextStreamId(); - } - - modifier whenNotDelegateCalled() { - _; - } - - modifier whenRecipientNonZeroAddress() { - _; - } - - modifier whenDepositAmountNotZero() { - _; - } - - modifier whenStartTimeNotZero() { - _; - } - - modifier whenStartTimeNotGreaterThanCliffTime() { - _; - } - - modifier whenCliffTimeLessThanEndTime() { - _; - } - - modifier whenEndTimeInTheFuture() { - _; - } - - modifier whenBrokerFeeNotTooHigh() { - _; - } - - modifier whenAssetContract() { - _; - } - - modifier whenAssetERC20() { - _; - } -} diff --git a/test/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/integration/shared/lockup-tranched/LockupTranched.t.sol index e9413d848..73d97ec2f 100644 --- a/test/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -52,14 +52,14 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithTimestamps(_params.createWithTimestamps); } - /// @dev Creates the default stream with the provided asset. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.asset = asset; streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided broker. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.broker = broker; @@ -81,7 +81,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithDurations(params); } - /// @dev Creates the default stream with the provided end time. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.tranches[2].timestamp = endTime; @@ -97,14 +97,14 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates a stream that will not be cancelable. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.cancelable = false; streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the NFT transfer disabled. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.transferable = false; @@ -119,7 +119,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.recipient = recipient; @@ -136,28 +136,28 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.sender = sender; streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided start time.. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.startTime = startTime; streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided total amount. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; params.totalAmount = totalAmount; streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided sender and recipient. + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithUsers( address recipient, address sender @@ -167,8 +167,8 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S returns (uint256 streamId) { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; params.recipient = recipient; + params.sender = sender; streamId = lockupTranched.createWithTimestamps(params); } } diff --git a/test/integration/shared/lockup-tranched/createWithDurations.t.sol b/test/integration/shared/lockup-tranched/createWithDurations.t.sol deleted file mode 100644 index ec4609379..000000000 --- a/test/integration/shared/lockup-tranched/createWithDurations.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; - -contract CreateWithDurations_Integration_Shared_Test is LockupTranched_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - streamId = lockupTranched.nextStreamId(); - } - - modifier whenNotDelegateCalled() { - _; - } - - modifier whenLoopCalculationsDoNotOverflowBlockGasLimit() { - _; - } - - modifier whenDurationsNotZero() { - _; - } - - modifier whenTimestampsCalculationsDoNotOverflow() { - _; - } -} diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/integration/shared/lockup/Lockup.t.sol index 6ee2a4d8e..b7da0ea18 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/integration/shared/lockup/Lockup.t.sol @@ -41,11 +41,6 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the NFT transfer disabled. function createDefaultStreamNotTransferable() internal virtual returns (uint256 streamId); - /// @dev Creates the default stream with recipient as the sender. - function createDefaultStreamToSender(address sender) internal virtual returns (uint256 streamId) { - return createDefaultStreamWithUsers(sender, sender); - } - /// @dev Creates the default stream with the provided address. function createDefaultStreamWithAsset(IERC20 asset) internal virtual returns (uint256 streamId); @@ -55,6 +50,11 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { /// @dev Creates the default stream with the provided end time. function createDefaultStreamWithEndTime(uint40 endTime) internal virtual returns (uint256 streamId); + /// @dev Creates the default stream with the provided user as the recipient and the sender. + function createDefaultStreamWithIdenticalUsers(address user) internal virtual returns (uint256 streamId) { + return createDefaultStreamWithUsers({ recipient: user, sender: user }); + } + /// @dev Creates the default stream with the provided recipient. function createDefaultStreamWithRecipient(address recipient) internal virtual returns (uint256 streamId); diff --git a/test/integration/shared/lockup-dynamic/createWithDurations.t.sol b/test/integration/shared/lockup/createWithDurations.t.sol similarity index 54% rename from test/integration/shared/lockup-dynamic/createWithDurations.t.sol rename to test/integration/shared/lockup/createWithDurations.t.sol index 31460ec2b..8446dc2c3 100644 --- a/test/integration/shared/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/shared/lockup/createWithDurations.t.sol @@ -1,16 +1,20 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; +import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; -contract CreateWithDurations_Integration_Shared_Test is LockupDynamic_Integration_Shared_Test { +abstract contract CreateWithDurations_Integration_Shared_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - streamId = lockupDynamic.nextStreamId(); + streamId = lockup.nextStreamId(); } - modifier whenNotDelegateCalled() { + modifier whenCliffDurationCalculationDoesNotOverflow() { + _; + } + + modifier whenDurationsNotZero() { _; } @@ -18,11 +22,15 @@ contract CreateWithDurations_Integration_Shared_Test is LockupDynamic_Integratio _; } - modifier whenDurationsNotZero() { + modifier whenNotDelegateCalled() { _; } modifier whenTimestampsCalculationsDoNotOverflow() { _; } + + modifier whenTotalDurationCalculationDoesNotOverflow() { + _; + } } diff --git a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol b/test/integration/shared/lockup/createWithTimestamps.t.sol similarity index 54% rename from test/integration/shared/lockup-tranched/createWithTimestamps.t.sol rename to test/integration/shared/lockup/createWithTimestamps.t.sol index 854d97960..252104613 100644 --- a/test/integration/shared/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/shared/lockup/createWithTimestamps.t.sol @@ -1,13 +1,53 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; +import { Lockup_Integration_Shared_Test } from "./Lockup.t.sol"; -contract CreateWithTimestamps_Integration_Shared_Test is LockupTranched_Integration_Shared_Test { +abstract contract CreateWithTimestamps_Integration_Shared_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - streamId = lockupTranched.nextStreamId(); + streamId = lockup.nextStreamId(); + } + + modifier whenAssetContract() { + _; + } + + modifier whenAssetERC20() { + _; + } + + modifier whenBrokerFeeNotTooHigh() { + _; + } + + modifier whenCliffTimeGreaterThanZero() { + _; + } + + modifier whenCliffTimeLessThanEndTime() { + _; + } + + modifier whenCliffTimeZero() { + _; + } + + modifier whenDepositAmountEqualToSegmentAmountsSum() { + _; + } + + modifier whenDepositAmountEqualToTrancheAmountsSum() { + _; + } + + modifier whenDepositAmountNotZero() { + _; + } + + modifier whenEndTimeInTheFuture() { + _; } modifier whenNotDelegateCalled() { @@ -18,51 +58,51 @@ contract CreateWithTimestamps_Integration_Shared_Test is LockupTranched_Integrat _; } - modifier whenDepositAmountNotZero() { + modifier whenSegmentAmountsSumDoesNotOverflow() { _; } - modifier whenStartTimeNotZero() { + modifier whenSegmentCountNotTooHigh() { _; } - modifier whenTrancheCountNotZero() { + modifier whenSegmentCountNotZero() { _; } - modifier whenTrancheCountNotTooHigh() { + modifier whenSegmentTimestampsOrdered() { _; } - modifier whenTrancheAmountsSumDoesNotOverflow() { + modifier whenStartTimeLessThanEndTime() { _; } - modifier whenStartTimeLessThanFirstTrancheTimestamp() { + modifier whenStartTimeLessThanFirstSegmentTimestamp() { _; } - modifier whenTrancheTimestampsOrdered() { + modifier whenStartTimeLessThanFirstTrancheTimestamp() { _; } - modifier whenEndTimeInTheFuture() { + modifier whenStartTimeNotZero() { _; } - modifier whenDepositAmountEqualToTrancheAmountsSum() { + modifier whenTrancheAmountsSumDoesNotOverflow() { _; } - modifier whenBrokerFeeNotTooHigh() { + modifier whenTrancheCountNotTooHigh() { _; } - modifier whenAssetContract() { + modifier whenTrancheCountNotZero() { _; } - modifier whenAssetERC20() { + modifier whenTrancheTimestampsOrdered() { _; } } diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index bf44eabb5..c6fb7d62c 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -120,7 +120,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 nextStreamId = lockup.nextStreamId(); - assertEq(nextStreamId, lastStreamId + 1, "Invariant violation: next stream id not incremented"); + assertEq(nextStreamId, lastStreamId + 1, "Invariant violation: next stream ID not incremented"); } } diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index 6c76c8d29..17bdd4ab3 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -58,7 +58,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { INVARIANTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The cliff time must be greater than the start time, if it is not zero. + /// @dev If it is not zero, the cliff time must be strictly greater than the start time. function invariant_CliffTimeGtStartTimeOrZero() external useCurrentTimestamp { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index 4cd0f7d7f..d918403f0 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -84,7 +84,7 @@ contract LockupDynamicCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupDynamic.createWithDurations(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } @@ -131,7 +131,7 @@ contract LockupDynamicCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupDynamic.createWithTimestamps(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } } diff --git a/test/invariant/handlers/LockupDynamicHandler.sol b/test/invariant/handlers/LockupDynamicHandler.sol index b18945add..29ec97aa8 100644 --- a/test/invariant/handlers/LockupDynamicHandler.sol +++ b/test/invariant/handlers/LockupDynamicHandler.sol @@ -9,7 +9,7 @@ import { LockupStore } from "../stores/LockupStore.sol"; import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupDynamic} is exposed to Foundry for invariant testing. The point is +/// @dev This contract and not {SablierV2LockupDynamic} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupDynamicHandler is LockupHandler { constructor( diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index f137b6f39..dcb145f3c 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -283,7 +283,7 @@ abstract contract LockupHandler is BaseHandler { // Make the max withdrawal and transfer the NFT. lockup.withdrawMaxAndTransfer({ streamId: currentStreamId, newRecipient: newRecipient }); - // Update the recipient associated with this stream id. + // Update the recipient associated with this stream ID. lockupStore.updateRecipient(currentStreamId, newRecipient); } @@ -320,7 +320,7 @@ abstract contract LockupHandler is BaseHandler { // Transfer the NFT to the new recipient. lockup.transferFrom({ from: currentRecipient, to: newRecipient, tokenId: currentStreamId }); - // Update the recipient associated with this stream id. + // Update the recipient associated with this stream ID. lockupStore.updateRecipient(currentStreamId, newRecipient); } } diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index cc6b7b498..ff8e3ac4f 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -73,7 +73,7 @@ contract LockupLinearCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupLinear.createWithDurations(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } @@ -92,19 +92,20 @@ contract LockupLinearCreateHandler is BaseHandler { return; } - uint40 currentTime = getBlockTimestamp(); + uint40 blockTimestamp = getBlockTimestamp(); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.range.start = boundUint40(params.range.start, 1, currentTime); - params.range.cliff = boundUint40(params.range.cliff, params.range.start + 1, params.range.start + 52 weeks); + params.range.start = boundUint40(params.range.start, 1 seconds, blockTimestamp); params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); - // Bound the end time so that it is always greater than both the current time and the cliff time (this is - // a requirement of the protocol). - params.range.end = boundUint40( - params.range.end, - (params.range.cliff <= currentTime ? currentTime : params.range.cliff) + 1 seconds, - MAX_UNIX_TIMESTAMP - ); + // The cliff time must be either zero or greater than the start time. + if (params.range.cliff > 0) { + params.range.cliff = + boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); + } + + // Bound the end time so that it is always greater than the start time, the cliff time, and the block timestamp. + uint40 endTimeLowerBound = maxOfThree(params.range.start, params.range.cliff, blockTimestamp); + params.range.end = boundUint40(params.range.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); @@ -116,7 +117,7 @@ contract LockupLinearCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupLinear.createWithTimestamps(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } } diff --git a/test/invariant/handlers/LockupLinearHandler.sol b/test/invariant/handlers/LockupLinearHandler.sol index 83bca10e4..f27fafccd 100644 --- a/test/invariant/handlers/LockupLinearHandler.sol +++ b/test/invariant/handlers/LockupLinearHandler.sol @@ -9,7 +9,7 @@ import { LockupStore } from "../stores/LockupStore.sol"; import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupLinear} is exposed to Foundry for invariant testing. The point is +/// @dev This contract and not {SablierV2LockupLinear} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupLinearHandler is LockupHandler { constructor( diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/invariant/handlers/LockupTranchedCreateHandler.sol index 6661a7863..8a292be82 100644 --- a/test/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/invariant/handlers/LockupTranchedCreateHandler.sol @@ -84,7 +84,7 @@ contract LockupTranchedCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupTranched.createWithDurations(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } @@ -131,7 +131,7 @@ contract LockupTranchedCreateHandler is BaseHandler { params.asset = asset; uint256 streamId = lockupTranched.createWithTimestamps(params); - // Store the stream id. + // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); } } diff --git a/test/invariant/handlers/LockupTranchedHandler.sol b/test/invariant/handlers/LockupTranchedHandler.sol index ab62a23fa..9194168e6 100644 --- a/test/invariant/handlers/LockupTranchedHandler.sol +++ b/test/invariant/handlers/LockupTranchedHandler.sol @@ -9,7 +9,7 @@ import { LockupStore } from "../stores/LockupStore.sol"; import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupTranched} is exposed to Foundry for invariant testing. The point is +/// @dev This contract and not {SablierV2LockupTranched} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupTranchedHandler is LockupHandler { constructor( diff --git a/test/invariant/stores/LockupStore.sol b/test/invariant/stores/LockupStore.sol index f74d5d0c7..0314ac96a 100644 --- a/test/invariant/stores/LockupStore.sol +++ b/test/invariant/stores/LockupStore.sol @@ -21,12 +21,12 @@ contract LockupStore { //////////////////////////////////////////////////////////////////////////*/ function pushStreamId(uint256 streamId, address sender, address recipient) external { - // Store the stream ids, the senders, and the recipients. + // Store the stream IDs, the senders, and the recipients. streamIds.push(streamId); senders[streamId] = sender; recipients[streamId] = recipient; - // Update the last stream id. + // Update the last stream ID. lastStreamId = streamId; } diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index 47bcf5aee..adac6ec55 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -52,7 +52,7 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { } function generateDescription_( - string memory streamingModel, + string memory sablierModel, string memory assetSymbol, string memory sablierAddress, string memory assetAddress, @@ -63,18 +63,11 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { pure returns (string memory) { - return generateDescription(streamingModel, assetSymbol, sablierAddress, assetAddress, streamId, isTransferable); + return generateDescription(sablierModel, assetSymbol, sablierAddress, assetAddress, streamId, isTransferable); } - function generateName_( - string memory streamingModel, - string memory streamId - ) - external - pure - returns (string memory) - { - return generateName(streamingModel, streamId); + function generateName_(string memory sablierModel, string memory streamId) external pure returns (string memory) { + return generateName(sablierModel, streamId); } function generateSVG_(NFTSVG.SVGParams memory params) external pure returns (string memory) { diff --git a/test/mocks/Noop.sol b/test/mocks/Noop.sol index 9b46e3a14..8f441ef3e 100644 --- a/test/mocks/Noop.sol +++ b/test/mocks/Noop.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; /// @dev This contract does nothing (no-op = no operation). diff --git a/test/mocks/erc721/ERC721Mock.sol b/test/mocks/erc721/ERC721Mock.sol deleted file mode 100644 index 004190ba6..000000000 --- a/test/mocks/erc721/ERC721Mock.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; - -contract ERC721Mock is ERC721 { - constructor(string memory name, string memory symbol) ERC721(name, symbol) { } -} diff --git a/test/unit/concrete/nft-descriptor/generateName.t.sol b/test/unit/concrete/nft-descriptor/generateName.t.sol index b65208ac8..3efedc0e5 100644 --- a/test/unit/concrete/nft-descriptor/generateName.t.sol +++ b/test/unit/concrete/nft-descriptor/generateName.t.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract GenerateName_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function gn(string memory streamingModel, string memory streamId) internal view returns (string memory) { - return nftDescriptorMock.generateName_(streamingModel, streamId); + function gn(string memory sablierModel, string memory streamId) internal view returns (string memory) { + return nftDescriptorMock.generateName_(sablierModel, streamId); } function dyn(string memory streamId) internal pure returns (string memory) { diff --git a/test/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/unit/concrete/nft-descriptor/generateSVG.t.sol index 8322a26ed..290a4c802 100644 --- a/test/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -22,8 +22,8 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { progress: "0%", progressNumerical: 0, sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - status: "Pending", - streamingModel: "Lockup Linear" + sablierModel: "Lockup Linear", + status: "Pending" }) ); string memory expectedSVG = @@ -42,8 +42,8 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { progress: "42.35%", progressNumerical: 4235, sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - status: "Streaming", - streamingModel: "Lockup Linear" + sablierModel: "Lockup Linear", + status: "Streaming" }) ); string memory expectedSVG = @@ -62,8 +62,8 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { progress: "100%", progressNumerical: 100, sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - status: "Depleted", - streamingModel: "Lockup Linear" + sablierModel: "Lockup Linear", + status: "Depleted" }) ); string memory expectedSVG = diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index a174981dc..7b2be5b81 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -41,32 +41,32 @@ abstract contract Assertions is PRBMathAssertions { assertEq(address(a), address(b), err); } - /// @dev Compares two {LockupLinear.Stream} struct entities. - function assertEq(LockupLinear.StreamLL memory a, LockupLinear.StreamLL memory b) internal { - assertEq(a.amounts, b.amounts); + /// @dev Compares two {LockupDynamic.Stream} struct entities. + function assertEq(LockupDynamic.StreamLD memory a, LockupDynamic.StreamLD memory b) internal { assertEq(a.asset, b.asset, "asset"); - assertEq(a.cliffTime, b.cliffTime, "cliffTime"); assertEq(a.endTime, b.endTime, "endTime"); assertEq(a.isCancelable, b.isCancelable, "isCancelable"); assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.recipient, b.recipient, "recipient"); + assertEq(a.segments, b.segments, "segments"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); } - /// @dev Compares two {LockupDynamic.Stream} struct entities. - function assertEq(LockupDynamic.StreamLD memory a, LockupDynamic.StreamLD memory b) internal { + /// @dev Compares two {LockupLinear.Stream} struct entities. + function assertEq(LockupLinear.StreamLL memory a, LockupLinear.StreamLL memory b) internal { + assertEq(a.amounts, b.amounts); assertEq(a.asset, b.asset, "asset"); + assertEq(a.cliffTime, b.cliffTime, "cliffTime"); assertEq(a.endTime, b.endTime, "endTime"); assertEq(a.isCancelable, b.isCancelable, "isCancelable"); assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.recipient, b.recipient, "recipient"); - assertEq(a.segments, b.segments, "segments"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); @@ -78,8 +78,8 @@ abstract contract Assertions is PRBMathAssertions { assertEq(a.endTime, b.endTime, "endTime"); assertEq(a.isCancelable, b.isCancelable, "isCancelable"); assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.isStream, b.isStream, "isStream"); + assertEq(a.isTransferable, b.isTransferable, "isTransferable"); assertEq(a.recipient, b.recipient, "recipient"); assertEq(a.sender, b.sender, "sender"); assertEq(a.startTime, b.startTime, "startTime"); @@ -87,15 +87,15 @@ abstract contract Assertions is PRBMathAssertions { assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); } - /// @dev Compares two {LockupLinear.Range} struct entities. - function assertEq(LockupLinear.Range memory a, LockupLinear.Range memory b) internal { - assertEqUint40(a.cliff, b.cliff, "range.cliff"); + /// @dev Compares two {LockupDynamic.Range} struct entities. + function assertEq(LockupDynamic.Range memory a, LockupDynamic.Range memory b) internal { assertEqUint40(a.end, b.end, "range.end"); assertEqUint40(a.start, b.start, "range.start"); } - /// @dev Compares two {LockupDynamic.Range} struct entities. - function assertEq(LockupDynamic.Range memory a, LockupDynamic.Range memory b) internal { + /// @dev Compares two {LockupLinear.Range} struct entities. + function assertEq(LockupLinear.Range memory a, LockupLinear.Range memory b) internal { + assertEqUint40(a.cliff, b.cliff, "range.cliff"); assertEqUint40(a.end, b.end, "range.end"); assertEqUint40(a.start, b.start, "range.start"); } @@ -106,7 +106,7 @@ abstract contract Assertions is PRBMathAssertions { assertEqUint40(a.start, b.start, "range.start"); } - /// @dev Compares two {LockupDynamic.Segment[]} arrays. + /// @dev Compares two {LockupDynamic.Segment} arrays. function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { emit log("Error: a == b not satisfied [LockupDynamic.Segment[]]"); @@ -116,7 +116,7 @@ abstract contract Assertions is PRBMathAssertions { } } - /// @dev Compares two `LockupDynamic.Segment[]` arrays. + /// @dev Compares two {LockupDynamic.Segment} arrays. function assertEq(LockupDynamic.Segment[] memory a, LockupDynamic.Segment[] memory b, string memory err) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { emit log_named_string("Error", err); @@ -124,7 +124,7 @@ abstract contract Assertions is PRBMathAssertions { } } - /// @dev Compares two {LockupTranched.Tranche[]} arrays. + /// @dev Compares two {LockupTranched.Tranche} arrays. function assertEq(LockupTranched.Tranche[] memory a, LockupTranched.Tranche[] memory b) internal { if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { emit log("Error: a == b not satisfied [LockupTranched.Tranche[]]"); @@ -134,7 +134,7 @@ abstract contract Assertions is PRBMathAssertions { } } - /// @dev Compares two `LockupTranched.Tranche[]` arrays. + /// @dev Compares two {LockupTranched.Tranche} arrays. function assertEq( LockupTranched.Tranche[] memory a, LockupTranched.Tranche[] memory b, diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index 2beda673a..1290e64bf 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -23,21 +23,21 @@ abstract contract Calculations { } /// @dev Helper function that replicates the logic of {SablierV2LockupLinear.streamedAmountOf}. - function calculateStreamedAmount(uint40 currentTime, uint128 depositAmount) internal view returns (uint128) { - if (currentTime > defaults.END_TIME()) { + function calculateStreamedAmount(uint40 blockTimestamp, uint128 depositAmount) internal view returns (uint128) { + if (blockTimestamp > defaults.END_TIME()) { return depositAmount; } unchecked { - UD60x18 elapsedTime = ud(currentTime - defaults.START_TIME()); - UD60x18 totalTime = ud(defaults.TOTAL_DURATION()); - UD60x18 elapsedTimePercentage = elapsedTime.div(totalTime); + UD60x18 elapsedTime = ud(blockTimestamp - defaults.START_TIME()); + UD60x18 totalDuration = ud(defaults.TOTAL_DURATION()); + UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); return elapsedTimePercentage.mul(ud(depositAmount)).intoUint128(); } } /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForMultipleSegments}. function calculateStreamedAmountForMultipleSegments( - uint40 currentTime, + uint40 blockTimestamp, LockupDynamic.Segment[] memory segments, uint128 depositAmount ) @@ -45,7 +45,7 @@ abstract contract Calculations { view returns (uint128) { - if (currentTime >= segments[segments.length - 1].timestamp) { + if (blockTimestamp >= segments[segments.length - 1].timestamp) { return depositAmount; } @@ -53,7 +53,7 @@ abstract contract Calculations { uint128 previousSegmentAmounts; uint40 currentSegmentTimestamp = segments[0].timestamp; uint256 index = 0; - while (currentSegmentTimestamp < currentTime) { + while (currentSegmentTimestamp < blockTimestamp) { previousSegmentAmounts += segments[index].amount; index += 1; currentSegmentTimestamp = segments[index].timestamp; @@ -70,11 +70,11 @@ abstract contract Calculations { previousTimestamp = defaults.START_TIME(); } - SD59x18 elapsedSegmentTime = (currentTime - previousTimestamp).intoSD59x18(); - SD59x18 totalSegmentTime = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); + SD59x18 elapsedTime = (blockTimestamp - previousTimestamp).intoSD59x18(); + SD59x18 segmentDuration = (currentSegmentTimestamp - previousTimestamp).intoSD59x18(); - SD59x18 elapsedSegmentTimePercentage = elapsedSegmentTime.div(totalSegmentTime); - SD59x18 multiplier = elapsedSegmentTimePercentage.pow(currentSegmentExponent); + SD59x18 elapsedTimePercentage = elapsedTime.div(segmentDuration); + SD59x18 multiplier = elapsedTimePercentage.pow(currentSegmentExponent); SD59x18 segmentStreamedAmount = multiplier.mul(currentSegmentAmount); return previousSegmentAmounts + uint128(segmentStreamedAmount.intoUint256()); } @@ -82,30 +82,30 @@ abstract contract Calculations { /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForOneSegment}. function calculateStreamedAmountForOneSegment( - uint40 currentTime, + uint40 blockTimestamp, LockupDynamic.Segment memory segment ) internal view returns (uint128) { - if (currentTime >= segment.timestamp) { + if (blockTimestamp >= segment.timestamp) { return segment.amount; } unchecked { - SD59x18 elapsedTime = (currentTime - defaults.START_TIME()).intoSD59x18(); - SD59x18 totalTime = (segment.timestamp - defaults.START_TIME()).intoSD59x18(); + SD59x18 elapsedTime = (blockTimestamp - defaults.START_TIME()).intoSD59x18(); + SD59x18 totalDuration = (segment.timestamp - defaults.START_TIME()).intoSD59x18(); - SD59x18 elapsedTimePercentage = elapsedTime.div(totalTime); + SD59x18 elapsedTimePercentage = elapsedTime.div(totalDuration); SD59x18 multiplier = elapsedTimePercentage.pow(segment.exponent.intoSD59x18()); - SD59x18 streamedAmountSd = multiplier.mul(segment.amount.intoSD59x18()); - return uint128(streamedAmountSd.intoUint256()); + SD59x18 streamedAmount = multiplier.mul(segment.amount.intoSD59x18()); + return uint128(streamedAmount.intoUint256()); } } /// @dev Helper function that replicates the logic of {SablierV2LockupTranched._calculateStreamedAmount}. function calculateStreamedAmountForTranches( - uint40 currentTime, + uint40 blockTimestamp, LockupTranched.Tranche[] memory tranches, uint128 depositAmount ) @@ -113,18 +113,18 @@ abstract contract Calculations { pure returns (uint128) { - if (currentTime >= tranches[tranches.length - 1].timestamp) { + if (blockTimestamp >= tranches[tranches.length - 1].timestamp) { return depositAmount; } - // Sum the amounts in all tranches that precede the current time. + // Sum the amounts in all tranches that precede the block timestamp. uint128 streamedAmount = tranches[0].amount; uint40 currentTrancheTimestamp = tranches[1].timestamp; uint256 index = 1; // Using unchecked arithmetic is safe because the tranches amounts sum equal to total amount at this point. unchecked { - while (currentTrancheTimestamp <= currentTime) { + while (currentTrancheTimestamp <= blockTimestamp) { streamedAmount += tranches[index].amount; index += 1; currentTrancheTimestamp = tranches[index].timestamp; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 8a22b5ec7..b39e36998 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -23,8 +23,9 @@ contract Defaults is Constants { uint40 public constant CLIFF_DURATION = 2500 seconds; uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - uint256 public constant MAX_COUNT = 500; + uint256 public constant MAX_SEGMENT_COUNT = 500; uint40 public immutable MAX_SEGMENT_DURATION; + uint256 public constant MAX_TRANCHE_COUNT = 500; uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; uint256 public SEGMENT_COUNT; uint40 public immutable START_TIME; @@ -45,7 +46,7 @@ contract Defaults is Constants { START_TIME = uint40(MAY_1_2024) + 2 days; CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; - MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_COUNT); + MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); SEGMENT_COUNT = 2; TRANCHE_COUNT = 3; WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index cb7418f99..226ac9af6 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -67,7 +67,8 @@ abstract contract DeployOptimized is StdCheats { function deployOptimizedCore( address initialAdmin, - uint256 maxCount + uint256 maxSegmentCount, + uint256 maxTrancheCount ) internal returns ( @@ -78,8 +79,8 @@ abstract contract DeployOptimized is StdCheats { ) { nftDescriptor_ = deployOptimizedNFTDescriptor(); - lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxCount); + lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxSegmentCount); lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, nftDescriptor_); - lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxCount); + lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxTrancheCount); } } diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index a4183491f..8496d4299 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -106,7 +106,7 @@ abstract contract Fuzzers is Constants, Utils { segments[segments.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); } - /// @dev Fuzzes the durations. + /// @dev Fuzzes the segment durations. function fuzzSegmentDurations(LockupDynamic.SegmentWithDuration[] memory segments) internal view { unchecked { // Precompute the first segment duration. @@ -127,8 +127,8 @@ abstract contract Fuzzers is Constants, Utils { uint40 segmentCount = uint40(segments.length); if (segmentCount == 1) { // The end time must be in the future. - uint40 currentTime = getBlockTimestamp(); - segments[0].timestamp = (startTime < currentTime ? currentTime : startTime) + 2 days; + uint40 blockTimestamp = getBlockTimestamp(); + segments[0].timestamp = (startTime < blockTimestamp ? blockTimestamp : startTime) + 2 days; return; } @@ -154,6 +154,50 @@ abstract contract Fuzzers is Constants, Utils { LOCKUP-TRANCHED //////////////////////////////////////////////////////////////////////////*/ + /// @dev Fuzzes the tranche durations. + function fuzzTrancheDurations(LockupTranched.TrancheWithDuration[] memory tranches) internal view { + unchecked { + // Precompute the first tranche duration. + tranches[0].duration = uint40(_bound(tranches[0].duration, 1, 100)); + + // Bound the durations so that none is zero and the calculations don't overflow. + uint256 durationCount = tranches.length; + uint40 maxDuration = (MAX_UNIX_TIMESTAMP - getBlockTimestamp()) / uint40(durationCount); + for (uint256 i = 1; i < durationCount; ++i) { + tranches[i].duration = boundUint40(tranches[i].duration, 1, maxDuration); + } + } + } + + /// @dev Fuzzes the tranche timestamps. + function fuzzTrancheTimestamps(LockupTranched.Tranche[] memory tranches, uint40 startTime) internal view { + // Return here if there's only one tranche to not run into division by zero. + uint40 trancheCount = uint40(tranches.length); + if (trancheCount == 1) { + // The end time must be in the future. + uint40 blockTimestamp = getBlockTimestamp(); + tranches[0].timestamp = (startTime < blockTimestamp ? blockTimestamp : startTime) + 2 days; + return; + } + + // The first timestamps is precomputed to avoid an underflow in the first loop iteration. We have to + // add 1 because the first timestamp must be greater than the start time. + tranches[0].timestamp = startTime + 1 seconds; + + // Fuzz the timestamps while preserving their order in the array. For each timestamp, set its initial guess + // as the sum of the starting timestamp and the step size multiplied by the current index. This ensures that + // the initial guesses are evenly spaced. Next, we bound the timestamp within a range of half the step size + // around the initial guess. + uint256 start = tranches[0].timestamp; + uint40 step = (MAX_UNIX_TIMESTAMP - tranches[0].timestamp) / (trancheCount - 1); + uint40 halfStep = step / 2; + for (uint256 i = 1; i < trancheCount; ++i) { + uint256 timestamp = start + i * step; + timestamp = _bound(timestamp, timestamp - halfStep, timestamp + halfStep); + tranches[i].timestamp = uint40(timestamp); + } + } + /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. function fuzzTranchedStreamAmounts(LockupTranched.Tranche[] memory tranches) internal @@ -240,48 +284,4 @@ abstract contract Fuzzers is Constants, Utils { createAmounts.deposit = totalAmount - createAmounts.brokerFee; tranches[tranches.length - 1].amount += (createAmounts.deposit - estimatedDepositAmount); } - - /// @dev Fuzzes the durations. - function fuzzTrancheDurations(LockupTranched.TrancheWithDuration[] memory tranches) internal view { - unchecked { - // Precompute the first tranche duration. - tranches[0].duration = uint40(_bound(tranches[0].duration, 1, 100)); - - // Bound the durations so that none is zero and the calculations don't overflow. - uint256 durationCount = tranches.length; - uint40 maxDuration = (MAX_UNIX_TIMESTAMP - getBlockTimestamp()) / uint40(durationCount); - for (uint256 i = 1; i < durationCount; ++i) { - tranches[i].duration = boundUint40(tranches[i].duration, 1, maxDuration); - } - } - } - - /// @dev Fuzzes the tranche timestamps. - function fuzzTrancheTimestamps(LockupTranched.Tranche[] memory tranches, uint40 startTime) internal view { - // Return here if there's only one tranche to not run into division by zero. - uint40 trancheCount = uint40(tranches.length); - if (trancheCount == 1) { - // The end time must be in the future. - uint40 currentTime = getBlockTimestamp(); - tranches[0].timestamp = (startTime < currentTime ? currentTime : startTime) + 2 days; - return; - } - - // The first timestamps is precomputed to avoid an underflow in the first loop iteration. We have to - // add 1 because the first timestamp must be greater than the start time. - tranches[0].timestamp = startTime + 1 seconds; - - // Fuzz the timestamps while preserving their order in the array. For each timestamp, set its initial guess - // as the sum of the starting timestamp and the step size multiplied by the current index. This ensures that - // the initial guesses are evenly spaced. Next, we bound the timestamp within a range of half the step size - // around the initial guess. - uint256 start = tranches[0].timestamp; - uint40 step = (MAX_UNIX_TIMESTAMP - tranches[0].timestamp) / (trancheCount - 1); - uint40 halfStep = step / 2; - for (uint256 i = 1; i < trancheCount; ++i) { - uint256 timestamp = start + i * step; - timestamp = _bound(timestamp, timestamp - halfStep, timestamp + halfStep); - tranches[i].timestamp = uint40(timestamp); - } - } } diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index d38753d7c..8272487e4 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -25,7 +25,7 @@ contract Precompiles_Test is Base_Test { function test_DeployLockupDynamic() external onlyTestOptimizedProfile { address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, nftDescriptor)); address expectedLockupDynamic = - address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, defaults.MAX_COUNT())); + address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT())); bytes memory expectedLockupDynamicCode = adjustBytecode(expectedLockupDynamic.code, expectedLockupDynamic, actualLockupDynamic); assertEq(actualLockupDynamic.code, expectedLockupDynamicCode, "bytecodes mismatch"); @@ -42,7 +42,7 @@ contract Precompiles_Test is Base_Test { function test_DeployLockupTranched() external onlyTestOptimizedProfile { address actualLockupTranched = address(precompiles.deployLockupTranched(users.admin, nftDescriptor)); address expectedLockupTranched = - address(deployOptimizedLockupTranched(users.admin, nftDescriptor, defaults.MAX_COUNT())); + address(deployOptimizedLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT())); bytes memory expectedLockupTranchedCode = adjustBytecode(expectedLockupTranched.code, expectedLockupTranched, actualLockupTranched); assertEq(actualLockupTranched.code, expectedLockupTranchedCode, "bytecodes mismatch"); @@ -67,7 +67,7 @@ contract Precompiles_Test is Base_Test { ISablierV2LockupLinear expectedLockupLinear, ISablierV2LockupTranched expectedLockupTranched, ISablierV2NFTDescriptor expectedNFTDescriptor - ) = deployOptimizedCore(users.admin, defaults.MAX_COUNT()); + ) = deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); bytes memory expectedLockupDynamicCode = adjustBytecode( address(expectedLockupDynamic).code, address(expectedLockupDynamic), address(actualLockupDynamic) diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 0a1b1b644..9a5257388 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -73,6 +73,18 @@ abstract contract Utils is CommonBase, PRBMathUtils { return Strings.equal(profile, "test-optimized"); } + /// @dev Returns the largest of the provided `uint40` numbers. + function maxOfThree(uint40 a, uint40 b, uint40 c) internal pure returns (uint40) { + uint40 max = a; + if (b > max) { + max = b; + } + if (c > max) { + max = c; + } + return max; + } + /// @dev Stops the active prank and sets a new one. function resetPrank(address msgSender) internal { vm.stopPrank(); From c6f189cf92107d8cefb7d72fd0e450289387ba2b Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 10 Apr 2024 02:22:14 +0100 Subject: [PATCH 084/132] test: order modifiers alphabetically (#885) --- test/integration/shared/lockup/cancel.t.sol | 32 +++++++++---------- .../shared/lockup/cancelMultiple.t.sol | 16 +++++----- .../shared/lockup/streamedAmountOf.t.sol | 6 ++-- test/integration/shared/lockup/withdraw.t.sol | 20 ++++++------ .../lockup/withdrawMaxAndTransfer.t.sol | 10 +++--- .../shared/lockup/withdrawMultiple.t.sol | 32 +++++++++---------- .../shared/lockup/withdrawableAmountOf.t.sol | 6 ++-- 7 files changed, 61 insertions(+), 61 deletions(-) diff --git a/test/integration/shared/lockup/cancel.t.sol b/test/integration/shared/lockup/cancel.t.sol index 9864b8455..a6f947bcd 100644 --- a/test/integration/shared/lockup/cancel.t.sol +++ b/test/integration/shared/lockup/cancel.t.sol @@ -11,55 +11,55 @@ abstract contract Cancel_Integration_Shared_Test is Lockup_Integration_Shared_Te resetPrank({ msgSender: users.sender }); } - modifier whenNotDelegateCalled() { + modifier givenNotNull() { _; } - modifier givenNotNull() { + modifier givenRecipientContract() { _; } - modifier givenStreamCold() { + modifier givenRecipientImplementsHook() { _; } - modifier givenStreamWarm() { + /// @dev In the LockupLinear contract, the streaming starts after the cliff time, whereas in the LockupDynamic + /// contract, the streaming starts after the start time. + modifier givenStatusStreaming() { + // Warp to the future, after the stream's start time but before the stream's end time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); _; } - modifier whenCallerUnauthorized() { + modifier givenStreamCancelable() { _; } - modifier whenCallerAuthorized() { + modifier givenStreamCold() { _; } - modifier givenStreamCancelable() { + modifier givenStreamWarm() { _; } - /// @dev In the LockupLinear contract, the streaming starts after the cliff time, whereas in the LockupDynamic - /// contract, the streaming starts after the start time. - modifier givenStatusStreaming() { - // Warp to the future, after the stream's start time but before the stream's end time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + modifier whenCallerAuthorized() { _; } - modifier givenRecipientContract() { + modifier whenCallerUnauthorized() { _; } - modifier givenRecipientImplementsHook() { + modifier whenNoRecipientReentrancy() { _; } - modifier whenRecipientDoesNotRevert() { + modifier whenNotDelegateCalled() { _; } - modifier whenNoRecipientReentrancy() { + modifier whenRecipientDoesNotRevert() { _; } } diff --git a/test/integration/shared/lockup/cancelMultiple.t.sol b/test/integration/shared/lockup/cancelMultiple.t.sol index e0af37aa7..1da602606 100644 --- a/test/integration/shared/lockup/cancelMultiple.t.sol +++ b/test/integration/shared/lockup/cancelMultiple.t.sol @@ -24,11 +24,11 @@ abstract contract CancelMultiple_Integration_Shared_Test is Lockup_Integration_S testStreamIds[1] = createDefaultStreamWithEndTime(defaults.END_TIME() + defaults.TOTAL_DURATION()); } - modifier whenNotDelegateCalled() { + modifier givenAllStreamsCancelable() { _; } - modifier whenArrayCountNotZero() { + modifier givenAllStreamsWarm() { _; } @@ -36,11 +36,7 @@ abstract contract CancelMultiple_Integration_Shared_Test is Lockup_Integration_S _; } - modifier givenAllStreamsWarm() { - _; - } - - modifier whenCallerUnauthorized() { + modifier whenArrayCountNotZero() { _; } @@ -52,7 +48,11 @@ abstract contract CancelMultiple_Integration_Shared_Test is Lockup_Integration_S _; } - modifier givenAllStreamsCancelable() { + modifier whenCallerUnauthorized() { + _; + } + + modifier whenNotDelegateCalled() { _; } } diff --git a/test/integration/shared/lockup/streamedAmountOf.t.sol b/test/integration/shared/lockup/streamedAmountOf.t.sol index fd9673265..bcacb2edf 100644 --- a/test/integration/shared/lockup/streamedAmountOf.t.sol +++ b/test/integration/shared/lockup/streamedAmountOf.t.sol @@ -14,15 +14,15 @@ abstract contract StreamedAmountOf_Integration_Shared_Test is Lockup_Integration _; } - modifier givenStreamHasBeenCanceled() { + modifier givenStatusStreaming() { _; } - modifier givenStreamHasNotBeenCanceled() { + modifier givenStreamHasBeenCanceled() { _; } - modifier givenStatusStreaming() { + modifier givenStreamHasNotBeenCanceled() { _; } diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index 11357aefb..dd2f968fc 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -11,10 +11,6 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ resetPrank({ msgSender: users.recipient }); } - modifier whenNotDelegateCalled() { - _; - } - modifier givenNotNull() { _; } @@ -32,19 +28,23 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } - modifier whenToNonZeroAddress() { + modifier whenCallerRecipient() { _; } - modifier whenWithdrawAmountNotZero() { + modifier whenNoOverdraw() { _; } - modifier whenNoOverdraw() { + modifier whenNotDelegateCalled() { _; } - modifier whenWithdrawalAddressNotRecipient() { + modifier whenStreamHasNotBeenCanceled() { + _; + } + + modifier whenToNonZeroAddress() { _; } @@ -52,11 +52,11 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } - modifier whenCallerRecipient() { + modifier whenWithdrawalAddressNotRecipient() { _; } - modifier whenStreamHasNotBeenCanceled() { + modifier whenWithdrawAmountNotZero() { _; } } diff --git a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol index 218e8d3ce..222cb78eb 100644 --- a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol @@ -11,7 +11,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Shared_Test is Lockup_Integ resetPrank({ msgSender: users.recipient }); } - modifier whenNotDelegateCalled() { + modifier givenNFTNotBurned() { _; } @@ -19,19 +19,19 @@ abstract contract WithdrawMaxAndTransfer_Integration_Shared_Test is Lockup_Integ _; } - modifier whenCallerCurrentRecipient() { + modifier givenStreamTransferable() { _; } - modifier givenStreamTransferable() { + modifier givenWithdrawableAmountNotZero() { _; } - modifier givenNFTNotBurned() { + modifier whenCallerCurrentRecipient() { _; } - modifier givenWithdrawableAmountNotZero() { + modifier whenNotDelegateCalled() { _; } } diff --git a/test/integration/shared/lockup/withdrawMultiple.t.sol b/test/integration/shared/lockup/withdrawMultiple.t.sol index 5b6e3ad9a..ca236ecff 100644 --- a/test/integration/shared/lockup/withdrawMultiple.t.sol +++ b/test/integration/shared/lockup/withdrawMultiple.t.sol @@ -37,15 +37,8 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration testStreamIds[2] = createDefaultStream(); } - modifier whenNotDelegateCalled() { - _; - } - - modifier whenToNonZeroAddress() { - _; - } - - modifier whenArraysEqual() { + modifier givenNoDepletedStream() { + vm.warp({ newTimestamp: defaults.START_TIME() }); _; } @@ -53,12 +46,7 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration _; } - modifier givenNoDepletedStream() { - vm.warp({ newTimestamp: defaults.START_TIME() }); - _; - } - - modifier whenCallerUnauthorized() { + modifier whenArraysEqual() { _; } @@ -82,11 +70,23 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration _; } - modifier whenNoAmountZero() { + modifier whenCallerUnauthorized() { _; } modifier whenNoAmountOverdraws() { _; } + + modifier whenNoAmountZero() { + _; + } + + modifier whenNotDelegateCalled() { + _; + } + + modifier whenToNonZeroAddress() { + _; + } } diff --git a/test/integration/shared/lockup/withdrawableAmountOf.t.sol b/test/integration/shared/lockup/withdrawableAmountOf.t.sol index 9abf213aa..624075f1d 100644 --- a/test/integration/shared/lockup/withdrawableAmountOf.t.sol +++ b/test/integration/shared/lockup/withdrawableAmountOf.t.sol @@ -13,15 +13,15 @@ abstract contract WithdrawableAmountOf_Integration_Shared_Test is Lockup_Integra _; } - modifier givenStreamHasBeenCanceled() { + modifier givenStatusStreaming() { _; } - modifier givenStreamHasNotBeenCanceled() { + modifier givenStreamHasBeenCanceled() { _; } - modifier givenStatusStreaming() { + modifier givenStreamHasNotBeenCanceled() { _; } } From 64accaceb40d1ff1b5486aaf6bc595e8c71e7c25 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 10 Apr 2024 17:22:37 +0100 Subject: [PATCH 085/132] perf: use unchecked to calculate sender amount --- src/abstracts/SablierV2Lockup.sol | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 6ca1f99de..e386f0c93 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -565,8 +565,13 @@ abstract contract SablierV2Lockup is revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); } - // Calculate the sender's and the recipient's amount. - uint128 senderAmount = amounts.deposited - streamedAmount; + // Calculate the sender's amount. + uint128 senderAmount; + unchecked { + senderAmount = amounts.deposited - streamedAmount; + } + + // Calculate the recipient's amount. uint128 recipientAmount = streamedAmount - amounts.withdrawn; // Effect: mark the stream as canceled. From e57553507b3a388c4a7245e04f36bd1dc014cbc0 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 10 Apr 2024 20:37:31 +0100 Subject: [PATCH 086/132] Fork tests for NFTDescriptor to check compatibility with v2.0 and v2.1 (#889) * test: bump block number for fork tests * test: NFTDescriptor compatibility test with v2.1 * test: update holder address for EURS fork tests * feat: low-level call for isTransferable in NFTDescriptor tokenURI * test: NFTDescriptor compatibility test with v2.0 * refactor: use "abi.encodeCall" chore: improve writing in comments refactor: put variables in "Vars" struct test: use "_bound" instead of "bound" * refactor: update precompiles --------- Co-authored-by: Paul Razvan Berg --- precompiles/Precompiles.sol | 8 +-- src/SablierV2NFTDescriptor.sol | 12 +++- test/fork/Fork.t.sol | 2 +- test/fork/NFTDescriptor.t.sol | 115 +++++++++++++++++++++++++++++++++ test/fork/assets/DAI.t.sol | 3 + test/fork/assets/EURS.t.sol | 5 +- test/fork/assets/SHIB.t.sol | 3 + test/fork/assets/USDC.t.sol | 3 + test/fork/assets/USDT.t.sol | 3 + 9 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 test/fork/NFTDescriptor.t.sol diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 105bf4add..2aa247bf8 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,13 +26,13 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f1962005a3c3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260075561563a9081620004028239608051816139a8015260a051818181610c9f0152613a6f0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146126d857508063027b6744146126b557806306fdde03146125ef578063081812fc146125d1578063095ea7b3146124d05780631400ecec1461242b5780631c1cdd4c146123c55780631e99d569146123a757806323b872dd1461239057806331df3d481461228457806340e58ee514611f8a578063425d30dd14611f3657806342842e0e14611efc57806342966c6814611d245780634426757014611cfd5780634857501f14611c875780634869e12d14611c4b5780634cc55e1114611b5057806354c02292146118cb5780636352211e1461189c5780636d0cee751461189c57806370a082311461182b57806375829def146117995780637cad6cd11461169e5780637de6b1db146114865780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d57610274612805565b6044356001600160801b038116810361029d5761029b9161029361399e565b6004356133a5565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a2612805565b6103ab82614244565b91612ff3565b3461029d57604036600319011261029d576103ca6127ef565b6103d2612805565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614244565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d8161293f565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff8251916105608361293f565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b28261373b565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f6040519282849384528301906127ca565b0390f35b9091503d806000833e610636818361298c565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b816129ae565b92610679604051948561298c565b81845284828401011161029d57610695918480850191016127a7565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c4612805565b6106cc61399e565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b65761071384614244565b6001600160801b0381166107a5575b508181161561078d57836107359161385d565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612ff3565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127ef565b6108e9612805565b6064359167ffffffffffffffff831161029d573660238401121561029d57826004013591610916836129ae565b92610924604051948561298c565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e7f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612def565b604051918291602083526020830190612895565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c906137d6565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127ef565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd69250038361298c565b61061f6040519282849384528301906127ca565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f906137d6565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612d9c565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e638461296f565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612dbb565b610120820152610efc6004356137d6565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e0850151151561010086015115159160043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612def565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190612895565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d57611157903690600401612864565b9061116061399e565b6000915b80831061116d57005b611178838284612d41565b359261118261399e565b83600052600980865260ff90600182816040600020015460a81c161561146f57866000528188526040600020838282015460a01c166000146111d65760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c611457576112028560005260096020526001600160a01b0360406000205416331490565b15611438576112108561375e565b91856000528089526112286002604060002001612dbb565b926001600160801b03948585511686831610156114205787600052828b5260406000205460f01c16156114085780858b6112686112729483895116612a02565b9601511690612a02565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50815496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161783558a6113578a8716998a156113ef575b60038096019b84169b8c6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132d8c878a614681565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61139a575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113e0575b80808061138a565b6113e99061295b565b856113d8565b898601600160a01b60ff60a01b198254161790556112db565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d57600435906114a461399e565b816000526009815260ff60016040600020015460a81c16156107d5576114c9826137d6565b6005811015610a4f57600481036114f25760248360405190634a5541ef60e01b82526004820152fd5b60038103611512576024836040519063fe19f19f60e01b82526004820152fd5b600214611686576115398260005260096020526001600160a01b0360406000205416331490565b1561166757816000526009815260ff60406000205460f01c161561164f578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115e0575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115b4576116499061295b565b836115b4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611770575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161175a5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117b26127ef565b6000546001600160a01b0380821692338403611804576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b0361184c6127ef565b16801561186b5760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118ba60043561373b565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d5761190861399e565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611942913691612c72565b9182519161194f83612c5a565b9261195d604051948561298c565b808452601f1961196c82612c5a565b018660005b828110611b3a5750505064ffffffffff90814216936001600160801b039687611999826139fa565b515116828a6119a7846139fa565b51015116858060406119b8866139fa565b5101511689011690604051926119cd84612923565b83528b83015260408201526119e1886139fa565b526119eb876139fa565b506001938760015b8a8c878310611ab95790838b8b611a0c81600401612d7b565b92611a1960248301612d7b565b92611a2660448401612d67565b946064840135946001600160a01b039586811680910361029d57611ab198611a7198611aa698611a5860848a01612d8f565b9481611a6660a48c01612d8f565b976040519d8e612906565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612d12565b610100820152613a1b565b604051908152f35b889385806040611aed8b86611add8a8e9a611ad4828d613a07565b5151169a613a07565b5101511694600019890190613a07565b51015116816040611afe888c613a07565b5101511601169160405193611b1285612923565b84528301526040820152611b26828c613a07565b52611b31818b613a07565b500188906119f3565b611b42612d9c565b828289010152018790611971565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b82903690600401612864565b9160243590811161029d57611b9b903690600401612864565b9091611ba561399e565b818403611c145760005b848110611bb857005b80611c0e611bc96001938886612d41565b35611bd5838987612d41565b3560005260036020526001600160a01b0360406000205416611c00611bfb85898b612d41565b612d67565b91611c0961399e565b6133a5565b01611baf565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610444602091614199565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cc3826137d6565b6005811015610a4f57600203611ce1575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cd4565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d4261399e565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ecb57611d8382614130565b156116675781600052600381526001600160a01b038060406000205416151580611ec3575b80611ea9575b611e91577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e56575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e3e57005b60249060405190637e27328960e01b82526004820152fd5b611e7785600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611dee565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615611dae565b506000611da8565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f0a3661282f565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e7f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611fa861399e565b8160005260099081815260ff60016040600020015460a81c161561226d5782600052818152604060002060ff600182015460a01c16600014611ffc5760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612255576120248360005260096020526001600160a01b0360406000205416331490565b15612236576120328361375e565b928060005282825261204a6002604060002001612dbb565b916001600160801b039485845116868216101561221e578260005284825260ff60406000205460f01c161561220657816120db82888796956120d17ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce796837f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa509b5116612a02565b9701511690612a02565b9383600052868252604060002096875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895560038a8216998a156121ec575b01998316998a6fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809716978891600386528860406000205416988994875260016040600020015416946121758d8588614681565b604080518a81526001600160801b0392831660208201529290911690820152606090a4604051838152a1813b6121a757005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e357005b61029b9061295b565b60018101600160a01b60ff60a01b19825416179055612122565b602483604051906339c6dc7360e21b82526004820152fd5b602483604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d576122bf61399e565b604051916122cc83612906565b6122d88260040161281b565b83526122e66024830161281b565b60208401526122f7604483016129ca565b604084015260648201356001600160a01b038116810361029d576060840152612322608483016128f9565b608084015261233360a483016128f9565b60a084015261234460c48301612c48565b60c084015260e482013590811161029d578101913660238401121561029d57611aa6611ab1926123806020953690602460048201359101612c72565b60e0840152610104369101612d12565b3461029d5761029b6123a13661282f565b91612a1b565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576123ff906137d6565b6005811015610a4f578060209115908115612420575b506040519015158152f35b600191501482612415565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c16806124be575b612495575b50506001600160801b0360405191168152f35b6124b792506001600160801b0360026124b1920154169161375e565b90612a02565b8280612482565b5060ff600182015460a01c161561247d565b3461029d57604036600319011261029d576124e96127ef565b6024356124f58161373b565b331515806125be575b80612590575b6125605781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff6040600020541615612504565b50336001600160a01b03821614156124fe565b3461029d57602036600319011261029d5760206118ba6004356129de565b3461029d57600036600319011261029d576040516000600190600154918260011c91600184169182156126ab575b6020948585108414610c67578587948686529182600014610c4757505060011461264e5750610bd69250038361298c565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612693575050610bd6935082010185610bc9565b8054838901850152879450869390920191810161267c565b92607f169261261d565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561277d575b8115612753575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361274c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612745565b60005b8381106127ba5750506000910152565b81810151838201526020016127aa565b906020916127e3815180928185528580860191016127a7565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b8281106128b5575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff1690860152606090940193928101926001016128a7565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b6129e78161373b565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175a57565b906001600160a01b03809116801561078d5760009184835260209160038352604092828486205416151580612c40575b80612c28575b612c11578685526003815282848620541694873315159384612b61575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612b29575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612afb5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b4a82600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612a97565b91929380915090612bd0575b15612b7b5790878392612a6e565b848887612b98576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612bf5575b80612b6d5750878252600583523384868420541614612b6d565b5085825260068352848220338352835260ff8583205416612bdb565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615612a51565b506001612a4b565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c7e82612c5a565b604094612c8e604051928361298c565b8195848352602080930191606080960285019481861161029d57925b858410612cba5750505050505050565b868483031261029d57825190612ccf82612923565b612cd8856129ca565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612d03868801612c48565b86820152815201930192612caa565b919082604091031261029d57604051612d2a8161293f565b6020808294612d388161281b565b84520135910152565b9190811015612d515760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612da982612923565b60006040838281528260208201520152565b90604051612dc881612923565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612dfb81612c5a565b92604093612e0c604051918261298c565b82815280946020809201926000526020600020906000935b858510612e3357505050505050565b60018481928451612e4381612923565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612e24565b9190612e8c828285612a1b565b803b612e99575b50505050565b612ef56001600160a01b03809216946040519384937f150b7a02000000000000000000000000000000000000000000000000000000009687865233600487015216602485015260448401526080606484015260848301906127ca565b03906020816000938185885af190829082612f8b575b5050612f425782612f1a614214565b8051919082612f3b5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f73575038808080612e93565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612feb575b81612fa86020938361298c565b81010312612fe75751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612fe45750903880612f0b565b80fd5b5080fd5b3d9150612f9b565b92919092612fff61399e565b60009381855260099260209380855260409260ff6001858a20015460a81c161561338f5784885281865260ff6001858a20015460a01c16613378576001600160a01b0391828216928315613361576001600160801b039384861691821561334a57888c5260038a5280888d20541693848314158061333a575b613317576130858a614244565b87811685116132e657508a8a928e928484528083528b8085209a8c848d54169c6002015460801c906130b69161426c565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130eb90612dbb565b90808683015116918184818351169201511661310691612a02565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d966132b9575b87825285522001541694613149818988614681565b8a51908152a480331415806132af575b61324a575b82331415908161323f575b81613234575b506131a3575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b15613230578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af1613221575b859481613175565b61322a9061295b565b38613219565b8780fd5b90508214153861316f565b833b15159150613169565b803b156132ab578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af161329c575b5061315e565b6132a59061295b565b38613296565b8880fd5b50803b1515613159565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613134565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506133448a614130565b15613078565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c161561338f578785815281875260ff6001868320015460a01c16613724576001600160a01b039081851692831561370d576001600160801b03938486169182156136f65789845260038b528489852054169485831415806136e6575b6136c35761344a8b838e61343683614199565b9289525260028c8820015460801c90612a02565b87811685116136925750908b8b928387528282528b808820998b838c54169b6002015460801c9061347a9161426c565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556134af90612dbb565b818086830151169381835116920151166134c891612a02565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613664575b848852825260018c88200154169461350c818c88614681565b8b51908152a4813314158061365a575b6135f4575b508133141590816135e9575b816135de575b50613566575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b156135da578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af16135c2575b8080613175565b6135cc869161295b565b6135d657846135bb565b8480fd5b8280fd5b905081141538613533565b823b1515915061352d565b813b15612fe4578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af1613646575b50613521565b61365291929a5061295b565b973880613640565b50813b151561351c565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134f3565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136f08b614130565b15613423565b60248a8a519063d2aabcd960e01b82526004820152fd5b602488885190630ff7ee2d60e31b82526004820152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e3e575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137cc5760c81c1611156137ba5750600a6020526001604060002054116000146137b1576137ae90614358565b90565b6137ae90614287565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137fd575050600490565b805460f81c613856575460a01c64ffffffffff164210613850576138208161375e565b9060005260096020526001600160801b03806002604060002001541691161060001461384b57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613993575b8061397b575b613964579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8483872054169485928361392c575b169283613916575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138f2565b61394d86600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138ea565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613889565b508181161515613883565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036139d057565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d515760200190565b8051821015612d515760209160051b010190565b90613a3d6001600160801b036040840151166020610100850151015190614537565b6001600160801b0381511660e084015164ffffffffff60c08601511682156141065780156140dc57815180156140b2577f00000000000000000000000000000000000000000000000000000000000000008111614081575064ffffffffff6040613aa6846139fa565b5101511681101561402a5750600090819082815184905b808210613f99575050505064ffffffffff421664ffffffffff8216811015613f595750506001600160801b0316808203613f22575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c598951996000198b0190613a07565b51015160c81b169560f01b16911617171717845560005b818110613e50575050600185016007556001600160a01b03602083015116801561078d57613ca6866001600160a01b039261385d565b16613e1f57613cd16001600160a01b036060840151166001600160801b038351169030903390614610565b6001600160801b0360208201511680613def575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613de4613dc560808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d6e8c61293f565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190612895565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613e19906001600160a01b036060850151166001600160a01b036101008601515116903390614610565b38613ce5565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e6d8160e0870151613a07565b518254680100000000000000008110156110eb5760018101808555811015612d5157600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c70565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613fbd906001600160801b03613fb48588613a07565b5151169061426c565b9364ffffffffff806040613fd18685613a07565b51015116941680851115613fed57506001849301909291613abd565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff604061403b846139fa565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614175575b5050821561416357505090565b90915061417033926129de565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614156565b8060005260096020526141b26002604060002001612dbb565b816000526009602052604060002060ff600182015460a01c166000146141e557506001600160801b039150602001511690565b5460f81c6141f757506137ae9061375e565b6137ae91506001600160801b036040818351169201511690612a02565b3d1561423f573d90614225826129ae565b91614233604051938461298c565b82523d6000602084013e565b606090565b6137ae9061425181614199565b90600052600960205260026040600020015460801c90612a02565b9190916001600160801b038080941691160191821161175a57565b64ffffffffff6142bc600091838352600960205280806040852054818160a01c1693849160c81c1603169181421603166146db565b91808252600a602052604082208054156143445790829167ffffffffffffffff9352614316602083205482845260096020526143116001600160801b03968760026040882001541696879360801c16906147cb565b614839565b92831361432c57505061432890614923565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161437e8361296f565b80549661012061440460026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612dbb565b94019384528452600a60205261441b858520612def565b9184968087614429866139fa565b5101511692828288955b16106145015750916144a7614311928488816144ac98976001600160801b039e8f61445e898c613a07565b5151169d8e9a67ffffffffffffffff60206144798c84613a07565b5101511699848361448a8385613a07565b510151169650806144e657505050511680925b03169203166146db565b6147cb565b9283136144c55750506144bf8391614923565b16011690565b5160200151929392831692841683101591506144e19050575090565b905090565b6144f69293506000190190613a07565b51015116809261449d565b8093986001600160801b0390816145188c89613a07565b51511601169801928282808a61452e888a613a07565b51015116614433565b919091604051906145478261293f565b600091828152826020820152936001600160801b03928383169182156145f15767016345785d8a00008082116145ba57506145838591846154eb565b16602087019281845211156145a6575090826145a192511690612a02565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906146058261293f565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761467f9260405261495f565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0392909216602483015260448083019390935291815261467f916146d660648361298c565b61495f565b600160ff1b8082149081156147c1575b5061479757600081121561478e57614714816000035b60008412156147875783600003906149fb565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614750576000199118131561474a5790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149fb565b61471481614701565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146eb565b806147e657506147e157670de0b6b3a764000090565b600090565b90670de0b6b3a764000080831461483357508061480b575050670de0b6b3a764000090565b670de0b6b3a7640000811461482f5761482a906143116137ae93614af5565b614c37565b5090565b91505090565b600160ff1b808214908115614919575b506148ef5760008112156148e657614872816000035b60008412156148df5783600003906154eb565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116148a8576000199118131561474a5790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154eb565b6148728161485f565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b9050821438614849565b6000811261492e5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b03169061498a600080836020829551910182875af1614983614214565b908461559a565b9081519182151592836149d3575b5050506149a25750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612fe7576020015190811591821503612fe45750388080614998565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614ab75782851015614a7b57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614ac5570490565b634e487b7160e01b600052601260045260246000fd5b8015614ac5576ec097ce7bc90715b34b9f10000000000590565b80600080831315614c0657670de0b6b3a764000092838112614be357506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614bd757506706f05b59d3b20000905b848213614bab5750505050500290565b808391020590671bc16d674ec80000821215614bca575b831d90614b9b565b8091950194831d90614bc2565b93505093925050020290565b6000199392508015614ac5576ec097ce7bc90715b34b9f10000000000591614b16565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c665768033dd1780914b9711419811261385057614c5d90600003614c37565b6137ae90614adb565b680a688906bd8affffff81136154ba57670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff00000000000000831661539d575b66ff0000000000008316615295575b65ff00000000008316615195575b64ff00000000831661509d575b63ff0000008316614fad575b62ff00008316614ec5575b61ff008316614de5575b60ff8316614d0e575b02911c60bf031c90565b60808316614dd3575b838316614dc1575b60208316614daf575b60108316614d9d575b60088316614d8b575b60048316614d79575b60028316614d67575b6001831615614d04576801000000000000000102831c614d04565b6801000000000000000102831c614d4c565b6801000000000000000302831c614d43565b6801000000000000000602831c614d3a565b6801000000000000000b02831c614d31565b6801000000000000001602831c614d28565b6801000000000000002c02831c614d1f565b6801000000000000005902831c614d17565b6180008316614eb3575b6140008316614ea1575b6120008316614e8f575b6110008316614e7d575b6108008316614e6b575b6104008316614e59575b6102008316614e47575b610100831615614cfb57680100000000000000b102831c614cfb565b6801000000000000016302831c614e2b565b680100000000000002c602831c614e21565b6801000000000000058c02831c614e17565b68010000000000000b1702831c614e0d565b6801000000000000162e02831c614e03565b68010000000000002c5d02831c614df9565b680100000000000058b902831c614def565b628000008316614f9b575b624000008316614f89575b622000008316614f77575b621000008316614f65575b620800008316614f53575b620400008316614f41575b620200008316614f2f575b62010000831615614cf1576801000000000000b17202831c614cf1565b680100000000000162e402831c614f12565b6801000000000002c5c802831c614f07565b68010000000000058b9102831c614efc565b680100000000000b172102831c614ef1565b68010000000000162e4302831c614ee6565b680100000000002c5c8602831c614edb565b6801000000000058b90c02831c614ed0565b6380000000831661508b575b63400000008316615079575b63200000008316615067575b63100000008316615055575b63080000008316615043575b63040000008316615031575b6302000000831661501f575b6301000000831615614ce65768010000000000b1721802831c614ce6565b6801000000000162e43002831c615001565b68010000000002c5c86002831c614ff5565b680100000000058b90c002831c614fe9565b6801000000000b17217f02831c614fdd565b680100000000162e42ff02831c614fd1565b6801000000002c5c85fe02831c614fc5565b68010000000058b90bfc02831c614fb9565b6480000000008316615183575b6440000000008316615171575b642000000000831661515f575b641000000000831661514d575b640800000000831661513b575b6404000000008316615129575b6402000000008316615117575b640100000000831615614cda57680100000000b17217f802831c614cda565b68010000000162e42ff102831c6150f8565b680100000002c5c85fe302831c6150eb565b6801000000058b90bfce02831c6150de565b68010000000b17217fbb02831c6150d1565b6801000000162e42fff002831c6150c4565b68010000002c5c8601cc02831c6150b7565b680100000058b90c0b4902831c6150aa565b658000000000008316615283575b654000000000008316615271575b65200000000000831661525f575b65100000000000831661524d575b65080000000000831661523b575b650400000000008316615229575b650200000000008316615217575b65010000000000831615614ccd576801000000b17218355102831c614ccd565b680100000162e430e5a202831c6151f7565b6801000002c5c863b73f02831c6151e9565b68010000058b90cf1e6e02831c6151db565b680100000b1721bcfc9a02831c6151cd565b68010000162e43f4f83102831c6151bf565b680100002c5c89d5ec6d02831c6151b1565b6801000058b91b5bc9ae02831c6151a3565b6680000000000000831661538b575b66400000000000008316615379575b66200000000000008316615367575b66100000000000008316615355575b66080000000000008316615343575b66040000000000008316615331575b6602000000000000831661531f575b6601000000000000831615614cbf5768010000b17255775c0402831c614cbf565b6801000162e525ee054702831c6152fe565b68010002c5cc37da949202831c6152ef565b680100058ba01fb9f96d02831c6152e0565b6801000b175effdc76ba02831c6152d1565b680100162f3904051fa102831c6152c2565b6801002c605e2e8cec5002831c6152b3565b68010058c86da1c09ea202831c6152a4565b678000000000000000831661549b575b6740000000000000008316615489575b6720000000000000008316615477575b6710000000000000008316615465575b6708000000000000008316615453575b6704000000000000008316615441575b670200000000000000831661542f575b670100000000000000831615614cb057680100b1afa5abcbed6102831c614cb0565b68010163da9fb33356d802831c61540d565b680102c9a3e778060ee702831c6153fd565b6801059b0d31585743ae02831c6153ed565b68010b5586cf9890f62a02831c6153dd565b6801172b83c7d517adce02831c6153cd565b6801306fe0a31b7152df02831c6153bd565b5077b504f333f9de6484800000000000000000000000000000006153ad565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461558957670de0b6b3a7640000908183101561555257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906155d957508051156155af57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580615624575b6155ea575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156155e256fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f19620059f23881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556155f090816200040282396080518161395e015260a051818181610c9f0152613a250152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461268e57508063027b67441461266b57806306fdde03146125a5578063081812fc14612587578063095ea7b3146124865780631400ecec146123e15780631c1cdd4c1461237b5780631e99d5691461235d57806323b872dd1461234657806331df3d481461223a57806340e58ee514611f80578063425d30dd14611f2c57806342842e0e14611ef257806342966c6814611d1a5780634426757014611cf35780634857501f14611c7d5780634869e12d14611c415780634cc55e1114611b4657806354c02292146118c15780636352211e146118925780636d0cee751461189257806370a082311461182157806375829def1461178f5780637cad6cd1146116945780637de6b1db1461147c5780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d576102746127bb565b6044356001600160801b038116810361029d5761029b91610293613954565b60043561335b565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a26127bb565b6103ab826141fa565b91612fa9565b3461029d57604036600319011261029d576103ca6127a5565b6103d26127bb565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141fa565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d816128f5565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff825191610560836128f5565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b2826136f1565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f604051928284938452830190612780565b0390f35b9091503d806000833e6106368183612942565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b81612964565b926106796040519485612942565b81845284828401011161029d576106959184808501910161275d565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c46127bb565b6106cc613954565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b657610713846141fa565b6001600160801b0381166107a5575b508181161561078d578361073591613813565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612fa9565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127a5565b6108e96127bb565b6064359167ffffffffffffffff831161029d573660238401121561029d5782600401359161091683612964565b926109246040519485612942565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612da5565b60405191829160208352602083019061284b565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c9061378c565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127a5565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612942565b61061f604051928284938452830190612780565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f9061378c565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612d52565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612925565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612d71565b610120820152610efc60043561378c565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e0850151151561010086015115159160043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612da5565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061284b565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d5761115790369060040161281a565b90611160613954565b6000915b80831061116d57005b611178838284612cf7565b3592611182613954565b83600052600980865260ff600181816040600020015460a81c161561146557866000528288526040600020828282015460a01c166000146111d55760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c61144d576112018560005260096020526001600160a01b0360406000205416331490565b1561142e5761120f85613714565b92856000528089526112276002604060002001612d71565b936001600160801b03938486511685831610156114165787600052828b5260406000205460f01c16156113fe5780848b8161126c94818a5116031697015116906129b8565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a61134d845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a156113e5575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132384878a614637565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b611390575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113d6575b808080611380565b6113df90612911565b856113ce565b898601600160a01b60ff60a01b198254161790556112d5565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d576004359061149a613954565b816000526009815260ff60016040600020015460a81c16156107d5576114bf8261378c565b6005811015610a4f57600481036114e85760248360405190634a5541ef60e01b82526004820152fd5b60038103611508576024836040519063fe19f19f60e01b82526004820152fd5b60021461167c5761152f8260005260096020526001600160a01b0360406000205416331490565b1561165d57816000526009815260ff60406000205460f01c1615611645578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115d6575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115aa5761163f90612911565b836115aa565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611766575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116117505760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117a86127a5565b6000546001600160a01b03808216923384036117fa576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b036118426127a5565b1680156118615760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118b06004356136f1565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d576118fe613954565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611938913691612c28565b9182519161194583612c10565b926119536040519485612942565b808452601f1961196282612c10565b018660005b828110611b305750505064ffffffffff90814216936001600160801b03968761198f826139b0565b515116828a61199d846139b0565b51015116858060406119ae866139b0565b5101511689011690604051926119c3846128d9565b83528b83015260408201526119d7886139b0565b526119e1876139b0565b506001938760015b8a8c878310611aaf5790838b8b611a0281600401612d31565b92611a0f60248301612d31565b92611a1c60448401612d1d565b946064840135946001600160a01b039586811680910361029d57611aa798611a6798611a9c98611a4e60848a01612d45565b9481611a5c60a48c01612d45565b976040519d8e6128bc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612cc8565b6101008201526139d1565b604051908152f35b889385806040611ae38b86611ad38a8e9a611aca828d6139bd565b5151169a6139bd565b51015116946000198901906139bd565b51015116816040611af4888c6139bd565b5101511601169160405193611b08856128d9565b84528301526040820152611b1c828c6139bd565b52611b27818b6139bd565b500188906119e9565b611b38612d52565b828289010152018790611967565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b7890369060040161281a565b9160243590811161029d57611b9190369060040161281a565b9091611b9b613954565b818403611c0a5760005b848110611bae57005b80611c04611bbf6001938886612cf7565b35611bcb838987612cf7565b3560005260036020526001600160a01b0360406000205416611bf6611bf185898b612cf7565b612d1d565b91611bff613954565b61335b565b01611ba5565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161414f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cb98261378c565b6005811015610a4f57600203611cd7575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cca565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d38613954565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ec157611d79826140e6565b1561165d5781600052600381526001600160a01b038060406000205416151580611eb9575b80611e9f575b611e87577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e4c575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e3457005b60249060405190637e27328960e01b82526004820152fd5b611e6d85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611de4565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615611da4565b506000611d9e565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f00366127e5565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611f9e613954565b81600052600980825260ff60016040600020015460a81c16156122235782600052808252604060002060ff600182015460a01c16600014611ff15760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61220b576120198360005260096020526001600160a01b0360406000205416331490565b156121ec5761202783613714565b8360005281835261203e6002604060002001612d71565b936001600160801b039182865116838216101561167c578160005283855260ff60406000205460f01c1615611645576120a6818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906129b8565b94826000528481526040600020956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895582169788156121d2575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5087604060002054169788938652600160406000200154169361215b8c8487614637565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b61218d57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121c957005b61029b90612911565b60018101600160a01b60ff60a01b198254161790556120ec565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d57612275613954565b60405191612282836128bc565b61228e826004016127d1565b835261229c602483016127d1565b60208401526122ad60448301612980565b604084015260648201356001600160a01b038116810361029d5760608401526122d8608483016128af565b60808401526122e960a483016128af565b60a08401526122fa60c48301612bfe565b60c084015260e482013590811161029d578101913660238401121561029d57611a9c611aa7926123366020953690602460048201359101612c28565b60e0840152610104369101612cc8565b3461029d5761029b612357366127e5565b916129d1565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576123b59061378c565b6005811015610a4f5780602091159081156123d6575b506040519015158152f35b6001915014826123cb565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c1680612474575b61244b575b50506001600160801b0360405191168152f35b61246d92506001600160801b0360026124679201541691613714565b906129b8565b8280612438565b5060ff600182015460a01c1615612433565b3461029d57604036600319011261029d5761249f6127a5565b6024356124ab816136f1565b33151580612574575b80612546575b6125165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff60406000205416156124ba565b50336001600160a01b03821614156124b4565b3461029d57602036600319011261029d5760206118b0600435612994565b3461029d57600036600319011261029d576040516000600190600154918260011c9160018416918215612661575b6020948585108414610c67578587948686529182600014610c475750506001146126045750610bd692500383612942565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612649575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612632565b92607f16926125d3565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612733575b8115612709575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612702565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126fb565b60005b8381106127705750506000910152565b8181015183820152602001612760565b906020916127998151809281855285808601910161275d565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b82811061286b575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161285d565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b61299d816136f1565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175057565b906001600160a01b03809116801561078d5760009184835260209160038352604092828486205416151580612bf6575b80612bde575b612bc7578685526003815282848620541694873315159384612b17575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612adf575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612ab15750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b0082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612a4d565b91929380915090612b86575b15612b315790878392612a24565b848887612b4e576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612bab575b80612b235750878252600583523384868420541614612b23565b5085825260068352848220338352835260ff8583205416612b91565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615612a07565b506001612a01565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c3482612c10565b604094612c446040519283612942565b8195848352602080930191606080960285019481861161029d57925b858410612c705750505050505050565b868483031261029d57825190612c85826128d9565b612c8e85612980565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612cb9868801612bfe565b86820152815201930192612c60565b919082604091031261029d57604051612ce0816128f5565b6020808294612cee816127d1565b84520135910152565b9190811015612d075760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612d5f826128d9565b60006040838281528260208201520152565b90604051612d7e816128d9565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612db181612c10565b92604093612dc26040519182612942565b82815280946020809201926000526020600020906000935b858510612de957505050505050565b60018481928451612df9816128d9565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612dda565b9190612e428282856129d1565b803b612e4f575b50505050565b612eab6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612780565b03906020816000938185885af190829082612f41575b5050612ef85782612ed06141ca565b8051919082612ef15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f29575038808080612e49565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612fa1575b81612f5e60209383612942565b81010312612f9d5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612f9a5750903880612ec1565b80fd5b5080fd5b3d9150612f51565b92919092612fb5613954565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133455784885281865260ff6001858a20015460a01c1661332e576001600160a01b0391828216928315613317576001600160801b039384861691821561330057888c5260038a5280888d2054169384831415806132f0575b6132cd5761303b8a6141fa565b878116851161329c57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061306c91614222565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130a190612d71565b9080868301511691818481835116920151166130bc916129b8565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9661326f575b878252855220015416946130ff818988614637565b8a51908152a48033141580613265575b613200575b8233141590816131f5575b816131ea575b50613159575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156131e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16131d7575b85948161312b565b6131e090612911565b386131cf565b8780fd5b905082141538613125565b833b1515915061311f565b803b15613261578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af1613252575b50613114565b61325b90612911565b3861324c565b8880fd5b50803b151561310f565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556130ea565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506132fa8a6140e6565b1561302e565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613345578785815281875260ff6001868320015460a01c166136da576001600160a01b03908185169283156136c3576001600160801b03938486169182156136ac5789845260038b5284898520541694858314158061369c575b613679576134008b838e6133ec8361414f565b9289525260028c8820015460801c906129b8565b87811685116136485750908b8b928387528282528b808820998b838c54169b6002015460801c9061343091614222565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561346590612d71565b8180868301511693818351169201511661347e916129b8565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361361a575b848852825260018c8820015416946134c2818c88614637565b8b51908152a48133141580613610575b6135aa575b5081331415908161359f575b81613594575b5061351c575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613590578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613578575b808061312b565b6135828691612911565b61358c5784613571565b8480fd5b8280fd5b9050811415386134e9565b823b151591506134e3565b813b15612f9a578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16135fc575b506134d7565b61360891929a50612911565b9738806135f6565b50813b15156134d2565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134a9565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136a68b6140e6565b156133d9565b60248a8a519063d2aabcd960e01b82526004820152fd5b602488885190630ff7ee2d60e31b82526004820152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e34575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137825760c81c1611156137705750600a602052600160406000205411600014613767576137649061430e565b90565b6137649061423d565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137b3575050600490565b805460f81c61380c575460a01c64ffffffffff164210613806576137d681613714565b9060005260096020526001600160801b03806002604060002001541691161060001461380157600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613949575b80613931575b61391a579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138e2575b1692836138cc575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a8565b61390386600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138a0565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561383f565b508181161515613839565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398657565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d075760200190565b8051821015612d075760209160051b010190565b906139f36001600160801b0360408401511660206101008501510151906144ed565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140bc5780156140925781518015614068577f00000000000000000000000000000000000000000000000000000000000000008111614037575064ffffffffff6040613a5c846139b0565b51015116811015613fe05750600090819082815184905b808210613f4f575050505064ffffffffff421664ffffffffff8216811015613f0f5750506001600160801b0316808203613ed8575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c0f8951996000198b01906139bd565b51015160c81b169560f01b16911617171717845560005b818110613e06575050600185016007556001600160a01b03602083015116801561078d57613c5c866001600160a01b0392613813565b16613dd557613c876001600160a01b036060840151166001600160801b0383511690309033906145c6565b6001600160801b0360208201511680613da5575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613d9a613d7b60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d248c6128f5565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061284b565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613dcf906001600160a01b036060850151166001600160a01b0361010086015151169033906145c6565b38613c9b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e238160e08701516139bd565b518254680100000000000000008110156110eb5760018101808555811015612d0757600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c26565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613f73906001600160801b03613f6a85886139bd565b51511690614222565b9364ffffffffff806040613f8786856139bd565b51015116941680851115613fa357506001849301909291613a73565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613ff1846139b0565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b03806040842054169283331493841561412b575b5050821561411957505090565b9091506141263392612994565b161490565b60ff929450906040918152600660205281812033825260205220541691388061410c565b8060005260096020526141686002604060002001612d71565b816000526009602052604060002060ff600182015460a01c1660001461419b57506001600160801b039150602001511690565b5460f81c6141ad575061376490613714565b61376491506001600160801b0360408183511692015116906129b8565b3d156141f5573d906141db82612964565b916141e96040519384612942565b82523d6000602084013e565b606090565b613764906142078161414f565b90600052600960205260026040600020015460801c906129b8565b9190916001600160801b038080941691160191821161175057565b64ffffffffff614272600091838352600960205280806040852054818160a01c1693849160c81c160316918142160316614691565b91808252600a602052604082208054156142fa5790829167ffffffffffffffff93526142cc602083205482845260096020526142c76001600160801b03968760026040882001541696879360801c1690614781565b6147ef565b9283136142e25750506142de906148d9565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161433483612925565b8054966101206143ba60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612d71565b94019384528452600a6020526143d1858520612da5565b91849680876143df866139b0565b5101511692828288955b16106144b757509161445d6142c79284888161446298976001600160801b039e8f614414898c6139bd565b5151169d8e9a67ffffffffffffffff602061442f8c846139bd565b5101511699848361444083856139bd565b5101511696508061449c57505050511680925b0316920316614691565b614781565b92831361447b57505061447583916148d9565b16011690565b5160200151929392831692841683101591506144979050575090565b905090565b6144ac92935060001901906139bd565b510151168092614453565b8093986001600160801b0390816144ce8c896139bd565b51511601169801928282808a6144e4888a6139bd565b510151166143e9565b919091604051906144fd826128f5565b600091828152826020820152936001600160801b03928383169182156145a75767016345785d8a000080821161457057506145398591846154a1565b166020870192818452111561455c57509082614557925116906129b8565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906145bb826128f5565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761463592604052614915565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146359161468c606483612942565b614915565b600160ff1b808214908115614777575b5061474d576000811215614744576146ca816000035b600084121561473d5783600003906149b1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470657600019911813156147005790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149b1565b6146ca816146b7565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146a1565b8061479c575061479757670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146147e95750806147c1575050670de0b6b3a764000090565b670de0b6b3a764000081146147e5576147e0906142c761376493614aab565b614bed565b5090565b91505090565b600160ff1b8082149081156148cf575b506148a557600081121561489c57614828816000035b60008412156148955783600003906154a1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485e57600019911813156147005790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154a1565b61482881614815565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386147ff565b600081126148e45790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614940600080836020829551910182875af16149396141ca565b9084615550565b908151918215159283614989575b5050506149585750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612f9d576020015190811591821503612f9a575038808061494e565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a6d5782851015614a3157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a7b570490565b634e487b7160e01b600052601260045260246000fd5b8015614a7b576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bbc57670de0b6b3a764000092838112614b9957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614b8d57506706f05b59d3b20000905b848213614b615750505050500290565b808391020590671bc16d674ec80000821215614b80575b831d90614b51565b8091950194831d90614b78565b93505093925050020290565b6000199392508015614a7b576ec097ce7bc90715b34b9f10000000000591614acc565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c1c5768033dd1780914b9711419811261380657614c1390600003614bed565b61376490614a91565b680a688906bd8affffff811361547057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615353575b66ff000000000000831661524b575b65ff0000000000831661514b575b64ff000000008316615053575b63ff0000008316614f63575b62ff00008316614e7b575b61ff008316614d9b575b60ff8316614cc4575b02911c60bf031c90565b60808316614d89575b838316614d77575b60208316614d65575b60108316614d53575b60088316614d41575b60048316614d2f575b60028316614d1d575b6001831615614cba576801000000000000000102831c614cba565b6801000000000000000102831c614d02565b6801000000000000000302831c614cf9565b6801000000000000000602831c614cf0565b6801000000000000000b02831c614ce7565b6801000000000000001602831c614cde565b6801000000000000002c02831c614cd5565b6801000000000000005902831c614ccd565b6180008316614e69575b6140008316614e57575b6120008316614e45575b6110008316614e33575b6108008316614e21575b6104008316614e0f575b6102008316614dfd575b610100831615614cb157680100000000000000b102831c614cb1565b6801000000000000016302831c614de1565b680100000000000002c602831c614dd7565b6801000000000000058c02831c614dcd565b68010000000000000b1702831c614dc3565b6801000000000000162e02831c614db9565b68010000000000002c5d02831c614daf565b680100000000000058b902831c614da5565b628000008316614f51575b624000008316614f3f575b622000008316614f2d575b621000008316614f1b575b620800008316614f09575b620400008316614ef7575b620200008316614ee5575b62010000831615614ca7576801000000000000b17202831c614ca7565b680100000000000162e402831c614ec8565b6801000000000002c5c802831c614ebd565b68010000000000058b9102831c614eb2565b680100000000000b172102831c614ea7565b68010000000000162e4302831c614e9c565b680100000000002c5c8602831c614e91565b6801000000000058b90c02831c614e86565b63800000008316615041575b6340000000831661502f575b6320000000831661501d575b6310000000831661500b575b63080000008316614ff9575b63040000008316614fe7575b63020000008316614fd5575b6301000000831615614c9c5768010000000000b1721802831c614c9c565b6801000000000162e43002831c614fb7565b68010000000002c5c86002831c614fab565b680100000000058b90c002831c614f9f565b6801000000000b17217f02831c614f93565b680100000000162e42ff02831c614f87565b6801000000002c5c85fe02831c614f7b565b68010000000058b90bfc02831c614f6f565b6480000000008316615139575b6440000000008316615127575b6420000000008316615115575b6410000000008316615103575b64080000000083166150f1575b64040000000083166150df575b64020000000083166150cd575b640100000000831615614c9057680100000000b17217f802831c614c90565b68010000000162e42ff102831c6150ae565b680100000002c5c85fe302831c6150a1565b6801000000058b90bfce02831c615094565b68010000000b17217fbb02831c615087565b6801000000162e42fff002831c61507a565b68010000002c5c8601cc02831c61506d565b680100000058b90c0b4902831c615060565b658000000000008316615239575b654000000000008316615227575b652000000000008316615215575b651000000000008316615203575b6508000000000083166151f1575b6504000000000083166151df575b6502000000000083166151cd575b65010000000000831615614c83576801000000b17218355102831c614c83565b680100000162e430e5a202831c6151ad565b6801000002c5c863b73f02831c61519f565b68010000058b90cf1e6e02831c615191565b680100000b1721bcfc9a02831c615183565b68010000162e43f4f83102831c615175565b680100002c5c89d5ec6d02831c615167565b6801000058b91b5bc9ae02831c615159565b66800000000000008316615341575b6640000000000000831661532f575b6620000000000000831661531d575b6610000000000000831661530b575b660800000000000083166152f9575b660400000000000083166152e7575b660200000000000083166152d5575b6601000000000000831615614c755768010000b17255775c0402831c614c75565b6801000162e525ee054702831c6152b4565b68010002c5cc37da949202831c6152a5565b680100058ba01fb9f96d02831c615296565b6801000b175effdc76ba02831c615287565b680100162f3904051fa102831c615278565b6801002c605e2e8cec5002831c615269565b68010058c86da1c09ea202831c61525a565b6780000000000000008316615451575b674000000000000000831661543f575b672000000000000000831661542d575b671000000000000000831661541b575b6708000000000000008316615409575b67040000000000000083166153f7575b67020000000000000083166153e5575b670100000000000000831615614c6657680100b1afa5abcbed6102831c614c66565b68010163da9fb33356d802831c6153c3565b680102c9a3e778060ee702831c6153b3565b6801059b0d31585743ae02831c6153a3565b68010b5586cf9890f62a02831c615393565b6801172b83c7d517adce02831c615383565b6801306fe0a31b7152df02831c615373565b5077b504f333f9de648480000000000000000000000000000000615363565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461553f57670de0b6b3a7640000908183101561550857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061558f575080511561556557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155da575b6155a0575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561559856fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f620049a63881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145c99081620003dd8239608051816139550152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f7457508063027b674414612f5157806306fdde0314612e8c578063081812fc14612e6d578063095ea7b314612d745780631400ecec14612cd45780631c1cdd4c14612c6f5780631e99d56914612c5157806323b872dd14612c3957806340e58ee5146129bb578063425d30dd1461296a57806342842e0e1461291a57806342966c6814612743578063442675701461271c5780634857501f146126a65780634869e12d1461266b5780634cc55e11146121c357806353b15727146120a45780636352211e146120745780636d0cee751461207457806370a082311461200457806375829def14611f71578063780a82c814611f245780637cad6cd114611e2a5780637de6b1db14611c035780638659c270146118b2578063894e9a0d146115925780638f69b993146114f65780639067b677146114a657806395d89b4114611397578063a22cb465146112da578063a80fc07114611288578063ab167ccc1461113e578063ad35efd4146110dc578063b25645691461108b578063b88d4fde14610ffe578063b8a3be6614610fc9578063b971302a14610f7a578063bc2be1be14610f2a578063c156a11d14610a65578063c87b56dd14610949578063cc364f481461087e578063d4dbd20b1461082c578063d511609f146107e0578063d975dfed14610794578063e985e9c51461073f578063ea5ead1914610717578063eac8f5b8146106c5578063f590c17614610663578063f851a4401461063d5763fdd46d601461025257600080fd5b3461063a57606036600319011261063a576004359061026f6130a3565b91610278613200565b9261028161394b565b818352600960209181835260ff600160408720015460a81c16156106235783855281835260ff600160408720015460a01c1661060b576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614132565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b6134f3565b906103b18186840151169282604081835116920151169061323a565b161115610532575b848c528252600160408c20015416946103d3818a8861415a565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b6104919061311f565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b6105199061311f565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d5896139a7565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461063a578060031936011261063a576001600160a01b036020915416604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a57600435906107356130a3565b9161027881614132565b503461063a57604036600319011261063a5761075961308d565b60406107636130a3565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091614132565b6001600160801b0360405191168152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57604082600292602094526009845220015460801c604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760036040836001600160801b0393602095526009855220015416604051908152f35b503461063a576020908160031936011261063a576004359161089e6134d4565b508282526009815260ff600160408420015460a81c16156109325760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c1691604051936108f985613150565b8452830152604082015261093060405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a5557600435610968816136a8565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a595780936109d8575b50506109d4604051928284938452830190613068565b0390f35b909192503d8082843e6109eb81846131c2565b8201918381840312610a555780519067ffffffffffffffff821161049c570182601f82011215610a5557805191610a21836131e4565b93610a2f60405195866131c2565b83855285848401011161063a575090610a4d91848085019101613045565b9038806109be565b5080fd5b604051903d90823e3d90fd5b503461063a57604036600319011261063a57600435610a826130a3565b610a8a61394b565b81835260099060209082825260ff600160408720015460a81c161561062357838552600382526001600160a01b03918260408720541693843303610f0b57610ad186614132565b906001600160801b039081831680158015610b71575b50505050505081811615610b595783610aff9161380a565b90811680610b1f5760248460405190637e27328960e01b82526004820152fd5b8203610b29578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b7961394b565b898b5282865260ff600160408d20015460a81c1615610ef457898b5282865260ff600160408d20015460a01c16610edc578815610ec457610eac57888a52600385528660408b205416918289141580610e9c575b610e7857610bda8a614132565b8481168311610e465750898b5280865260408b20938260028a87541696015460801c01818111610e325790610c418d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c5d818a840151169282604081835116920151169061323a565b161115610e03575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610ca481868861415a565b604051908152a48033141580610df9575b610d8f575b813314159081610d84575b81610d79575b50610d08575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610ae7565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d61575b80610cd1565b610d6a9061311f565b610d75578538610d5b565b8580fd5b905081141538610ccb565b823b15159150610cc5565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610de5575b5050610cba565b610dee9061311f565b6104a0578338610dde565b50803b1515610cb5565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c65565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ea68a6139a7565b15610bcd565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae576040826001600160a01b03926020945260098452205416604051908152f35b503461063a57602036600319011261063a5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063a57608036600319011261063a5761101861308d565b6110206130a3565b906064359067ffffffffffffffff82116104a057366023830112156104a0578160040135928461104f856131e4565b9361105d60405195866131c2565b8585523660248783010111610a5557856110889660246020930183880137850101526044359161353b565b80f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761111590613783565b60405190600581101561112a57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063a5761014036600319011261063a5761115961394b565b6111616134d4565b9064ffffffffff80421680845281611177613527565b16611272575b60e43590828216820361126d5701166040830152600435916001600160a01b039182841680940361126d576024359083821680920361126d57604435906001600160801b03821680920361126d576064359085821680920361063a57506084359182151580930361126d5760a4359384151580950361126d576040519761120389613133565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126d576040519161123d836131a6565b61010435918216820361126d57826112659260209452610124358482015260e0820152613a8e565b604051908152f35b600080fd5b8161127b613527565b820116602085015261117d565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760026040836001600160801b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a576112f461308d565b6024359081151580920361126d576001600160a01b03169081156113665733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a578060031936011261063a5760405190806002549160018360011c926001851694851561149c575b60209586861081146114885785885287949392918790821561146657505060011461140c575b50506113f8925003836131c2565b6109d4604051928284938452830190613068565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144e5750506113f8935082010138806113ea565b80548389018501528794508693909201918101611436565b92509350506113f894915060ff191682840152151560051b82010138806113ea565b602483634e487b7160e01b81526022600452fd5b93607f16936113c4565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761152f90613783565b90600582101590816115705760028314918215611584575b821561155b575b6020836040519015158152f35b9091506115705750600460209114388061154e565b80634e487b7160e01b602492526021600452fd5b506003831491506000611547565b503461063a57602036600319011261063a57806101606040516115b48161316c565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f76134d4565b61014082015201526004358152600960205260ff600160408320015460a81c161561189a576004358152600960205260408120906116c560026040519361163d85613189565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c161515610100860152016134f3565b6101208301526116d6600435613783565b6005811015611886576101606101c093600264ffffffffff931461187b575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117828d61316c565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f5565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063a57602080600319360112610a555760043567ffffffffffffffff811161049c576118e59036906004016130ee565b91906118ef61394b565b83925b8084106118fd578480f35b6119088482846134ae565b359361191261394b565b848652600980855260ff90600190828260408b20015460a81c1615611bec57878952808752604089208281015460a01c8416156119615760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd4576119928160005260096020526001600160a01b0360406000205416331490565b15611bb4576119a0816136cb565b818a528289526119b5600260408c20016134f3565b906001600160801b0395868351168783161015611b9c57838c52848b5260408c205460f01c1615611b845791818a611a0685898f9a9998966119fc8c99838793511661323a565b950151169061323a565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611b6b575b60038096019c88169c8d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611ab08b858861415a565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b14575b5050505050506001019291906118f2565b813b15610d7557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b57575b80808080611b03565b611b609061311f565b610524578438611b4e565b818601600160a01b60ff60a01b19825416179055611a6b565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a555760043590611c2261394b565b8183526009815260ff600160408520015460a81c1615611e1357611c4582613783565b6005811015611dff5760048103611c6e5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8e576024836040519063fe19f19f60e01b82526004820152fd5b600214611de757611cb58260005260096020526001600160a01b0360406000205416331490565b15611dc8578183526009815260ff604084205460f01c1615611db057818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d58575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9c575b80611d29565b611da59061311f565b61049c578238611d96565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a576004356001600160a01b039081811680910361049c5781835416338103611efb575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee75760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063a57602036600319011261063a57611f8b61308d565b9080546001600160a01b0380821693338503611fdd576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461063a57602036600319011261063a576001600160a01b0361202661308d565b168015612043578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57602036600319011261063a5760206120936004356136a8565b6001600160a01b0360405191168152f35b503461063a5761016036600319011261063a576120bf61394b565b604051906120cc82613133565b6120d461308d565b82526120de6130a3565b60208301526120eb613200565b60408301526001600160a01b03906064358281168103610a55576060840152608435801515810361126d57608084015260a435801515810361126d5760a084015260603660c319011261063a575060405161214581613150565b64ffffffffff60c435818116810361126d57825260e435818116810361126d57602083015261010435908116810361126d57604082015260c083015260406101231936011261126d576040519161219b836131a6565b61012435918216820361126d57826112659260209452610144358482015260e0820152613a8e565b503461063a57604036600319011261063a5767ffffffffffffffff60043581811161049c576121f69036906004016130ee565b90916024359081116104a0576122109036906004016130ee565b61221861394b565b80830361263457845b83811061222c578580f35b6122378185876134ae565b35906122448186886134ae565b35875260036020526001600160a01b036040882054166122658285876134ae565b35906001600160801b038216820361126d5761227f61394b565b838952600960205260ff600160408b20015460a81c161561062357838952600960205260ff600160408b20015460a01c1661060b57801561261c576001600160801b038216156126045783895260036020526001600160a01b0360408a2054169182821415806125f4575b6125d0576122f785614132565b6001600160801b0381166001600160801b038316116125a05750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123888c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ac816020840151169282604081835116920151169061323a565b16111561256f575b86855260096020526001600160a01b036001604087200154166123e16001600160801b038416858361415a565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612565575b6124fb575b8333141590816124f0575b816124e5575b50612473575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612221565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124cd575b808061243c565b6124d69061311f565b6124e15786386124c6565b8680fd5b905083141538612436565b843b15159150612430565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612551575b5050612425565b61255a9061311f565b61052457843861254a565b50803b1515612420565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b4565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125fe856139a7565b156122ea565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091613a10565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1357806126e183613783565b92600584101561188657600260209403612702575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126f6565b503461063a578060031936011261063a5760206001600160a01b0360085416604051908152f35b503461063a57602080600319360112610a55576004359061276261394b565b8183526009815260ff600160408520015460a81c1615611e13578183526009815260ff600160408520015460a01c16156128e95761279f826139a7565b15611dc85781600052600381526001600160a01b0380604060002054161515806128e1575b806128c7575b6128af577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612874575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161285c575080f35b60249060405190637e27328960e01b82526004820152fd5b61289585600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561280a565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c16156127ca565b5060006127c4565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57612929366130b9565b60405191602083019383851067ffffffffffffffff861117612954576110889460405285845261353b565b634e487b7160e01b600052604160045260246000fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063a576020908160031936011261063a57600435906129db61394b565b81815260099283815260ff600160408420015460a81c16156109325782825283815260408220600181015460a01c60ff1615612a295760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611bd457612a548160005260096020526001600160a01b0360406000205416331490565b15611bb457612a62816136cb565b93818452808352612a78600260408620016134f3565b916001600160801b0393848451168588161015611de75781865282815260ff604087205460f01c1615611db057612ac6878683612abc8a9b838a9c9b9c511661323a565b970151169061323a565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612c1f575b01988716988981546001600160801b0319161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612b528c848761415a565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612bce578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c10575b81818080808480f35b612c199061311f565b81612c07565b60018101600160a01b60ff60a01b19825416179055612b0b565b503461063a57611088612c4b366130b9565b91613269565b503461063a578060031936011261063a576020600754604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57612ca890613783565b9060058210156115705760208215838115612cc9575b506040519015158152f35b600191501482612cbe565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1357602091604082828152600985522060ff815460f01c1680612d62575b612d39575b50506001600160801b0360405191168152f35b612d5b92506001600160801b036002612d5592015416916136cb565b9061323a565b3880612d26565b5060ff600182015460a01c1615612d21565b503461063a57604036600319011261063a57612d8e61308d565b602435612d9a816136a8565b33151580612e5a575b80612e30575b612e005781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612da9565b50336001600160a01b0382161415612da3565b503461063a57602036600319011261063a576020612093600435613216565b503461063a578060031936011261063a576040519080600191600154928360011c9260018516948515612f47575b602095868610811461148857858852879493929187908215611466575050600114612eed5750506113f8925003836131c2565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f2f5750506113f8935082010138806113ea565b80548389018501528794508693909201918101612f17565b93607f1693612eba565b503461063a578060031936011261063a57602060405167016345785d8a00008152f35b905034610a55576020366003190112610a55576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561301b575b8115612ff1575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438612fea565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612fe3565b60005b8381106130585750506000910152565b8181015183820152602001613048565b9060209161308181518092818552858086019101613045565b601f01601f1916010190565b600435906001600160a01b038216820361126d57565b602435906001600160a01b038216820361126d57565b606090600319011261126d576001600160a01b0390600435828116810361126d5791602435908116810361126d579060443590565b9181601f8401121561126d5782359167ffffffffffffffff831161126d576020808501948460051b01011161126d57565b67ffffffffffffffff811161295457604052565b610100810190811067ffffffffffffffff82111761295457604052565b6060810190811067ffffffffffffffff82111761295457604052565b610180810190811067ffffffffffffffff82111761295457604052565b610140810190811067ffffffffffffffff82111761295457604052565b6040810190811067ffffffffffffffff82111761295457604052565b90601f8019910116810190811067ffffffffffffffff82111761295457604052565b67ffffffffffffffff811161295457601f01601f191660200190565b604435906001600160801b038216820361126d57565b61321f816136a8565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161325357565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b038091168015613496576000918483526020916003835260409282848620541615158061348e575b80613476575b61345f5786855260038152828486205416948733151593846133af575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087613377575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036133495750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61339882600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132e5565b9192938091509061341e575b156133c957908783926132bc565b8488876133e6576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613443575b806133bb57508782526005835233848684205416146133bb565b5085825260068352848220338352835260ff8583205416613429565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c161561329f565b506001613299565b6024604051633250574960e11b815260006004820152fd5b91908110156134be5760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134e182613150565b60006040838281528260208201520152565b9060405161350081613150565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361126d5790565b9190613548828285613269565b803b613555575b50505050565b6135b16001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613068565b03906020816000938185885af190829082613647575b50506135fe57826135d6614102565b80519190826135f75760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361362f57503880808061354f565b60249060405190633250574960e11b82526004820152fd5b909192506020813d6020116136a0575b81613664602093836131c2565b81010312610a555751907fffffffff000000000000000000000000000000000000000000000000000000008216820361063a57509038806135c7565b3d9150613657565b8060005260036020526001600160a01b036040600020541690811561285c575090565b600090808252600a60205264ffffffffff9182604082205416421061377d5760096020526040812092835490808260c81c1691824210156137675761371c9394955060a01c168091039042036142fe565b9082815260096020526001600160801b03926137428460026040852001541680946143de565b92831161374f5750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c166000146137aa575050600490565b805460f81c613803575460a01c64ffffffffff1642106137fd576137cd816136cb565b9060005260096020526001600160801b0380600260406000200154169116106000146137f857600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613940575b80613928575b613911579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138d9575b1692836138c3575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b838752600488528087206001815401905561389f565b6138fa86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613897565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613836565b508181161515613830565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361397d57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b0380604084205416928333149384156139ec575b505082156139da57505090565b9091506139e73392613216565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139cd565b806000526009602052613a2960026040600020016134f3565b816000526009602052604060002060ff600182015460a01c16600014613a5c57506001600160801b039150602001511690565b5460f81c613a715750613a6e906136cb565b90565b613a6e91506001600160801b03604081835116920151169061323a565b90613aaf6001600160801b03604084015116602060e08501510151906141b6565b916001600160801b0383511660c082015190156140d85764ffffffffff815116156140ae576020810164ffffffffff81511680613ffe575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fbe57505064ffffffffff8042169151169081811015613f7e575050600754926001600160801b0381511660405190613b3e82613150565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613ba088613189565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613d9884875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f60575b50600184016007556001600160a01b03602083015116801561349657613de8856001600160a01b039261380a565b16613f2f57613e136001600160a01b036060840151166001600160801b03835116903090339061428f565b6001600160801b0360208201511680613f00575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613ef76001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f29906001600160a01b036060850151166001600160a01b0360e0860151511690339061428f565b38613e27565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dba565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561406e57505064ffffffffff90511664ffffffffff60408301511690818110613ae7576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d1561412d573d90614113826131e4565b9161412160405193846131c2565b82523d6000602084013e565b606090565b613a6e9061413f81613a10565b90600052600960205260026040600020015460801c9061323a565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141b4916141af6064836131c2565b61448d565b565b919091604051906141c6826131a6565b600091828152826020820152936001600160801b03928383169182156142705767016345785d8a000080821161423957506142028591846143de565b1660208701928184521115614225575090826142209251169061323a565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5093945050505060405190614284826131a6565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612954576141b49260405261448d565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143ba578285101561437e57908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143c8570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461447c57670de0b6b3a7640000908183101561444557947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144b8600080836020829551910182875af16144b1614102565b9084614529565b908151918215159283614501575b5050506144d05750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a5557602001519081159182150361063a57503880806144c6565b90614568575080511561453e57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145b3575b614579575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561457156fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f620049bc3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145df9081620003dd82396080518161396b0152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f8a57508063027b674414612f6757806306fdde0314612ea2578063081812fc14612e83578063095ea7b314612d8a5780631400ecec14612cea5780631c1cdd4c14612c855780631e99d56914612c6757806323b872dd14612c4f57806340e58ee5146129bc578063425d30dd1461296b57806342842e0e1461291b57806342966c6814612744578063442675701461271d5780634857501f146126a75780634869e12d1461266c5780634cc55e11146121c457806353b15727146120a55780636352211e146120755780636d0cee751461207557806370a082311461200557806375829def14611f72578063780a82c814611f255780637cad6cd114611e2b5780637de6b1db14611c045780638659c270146118b2578063894e9a0d146115925780638f69b993146114f65780639067b677146114a657806395d89b4114611397578063a22cb465146112da578063a80fc07114611288578063ab167ccc1461113e578063ad35efd4146110dc578063b25645691461108b578063b88d4fde14610ffe578063b8a3be6614610fc9578063b971302a14610f7a578063bc2be1be14610f2a578063c156a11d14610a65578063c87b56dd14610949578063cc364f481461087e578063d4dbd20b1461082c578063d511609f146107e0578063d975dfed14610794578063e985e9c51461073f578063ea5ead1914610717578063eac8f5b8146106c5578063f590c17614610663578063f851a4401461063d5763fdd46d601461025257600080fd5b3461063a57606036600319011261063a576004359061026f6130b9565b91610278613216565b92610281613961565b818352600960209181835260ff600160408720015460a81c16156106235783855281835260ff600160408720015460a01c1661060b576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614148565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b613509565b906103b181868401511692826040818351169201511690613250565b161115610532575b848c528252600160408c20015416946103d3818a88614170565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613135565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613135565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d5896139bd565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461063a578060031936011261063a576001600160a01b036020915416604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a57600435906107356130b9565b9161027881614148565b503461063a57604036600319011261063a576107596130a3565b60406107636130b9565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091614148565b6001600160801b0360405191168152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57604082600292602094526009845220015460801c604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760036040836001600160801b0393602095526009855220015416604051908152f35b503461063a576020908160031936011261063a576004359161089e6134ea565b508282526009815260ff600160408420015460a81c16156109325760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c1691604051936108f985613166565b8452830152604082015261093060405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a5557600435610968816136be565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a595780936109d8575b50506109d460405192828493845283019061307e565b0390f35b909192503d8082843e6109eb81846131d8565b8201918381840312610a555780519067ffffffffffffffff821161049c570182601f82011215610a5557805191610a21836131fa565b93610a2f60405195866131d8565b83855285848401011161063a575090610a4d9184808501910161305b565b9038806109be565b5080fd5b604051903d90823e3d90fd5b503461063a57604036600319011261063a57600435610a826130b9565b610a8a613961565b81835260099060209082825260ff600160408720015460a81c161561062357838552600382526001600160a01b03918260408720541693843303610f0b57610ad186614148565b906001600160801b039081831680158015610b71575b50505050505081811615610b595783610aff91613820565b90811680610b1f5760248460405190637e27328960e01b82526004820152fd5b8203610b29578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b79613961565b898b5282865260ff600160408d20015460a81c1615610ef457898b5282865260ff600160408d20015460a01c16610edc578815610ec457610eac57888a52600385528660408b205416918289141580610e9c575b610e7857610bda8a614148565b8481168311610e465750898b5280865260408b20938260028a87541696015460801c01818111610e325790610c418d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c5d818a8401511692826040818351169201511690613250565b161115610e03575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610ca4818688614170565b604051908152a48033141580610df9575b610d8f575b813314159081610d84575b81610d79575b50610d08575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610ae7565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d61575b80610cd1565b610d6a90613135565b610d75578538610d5b565b8580fd5b905081141538610ccb565b823b15159150610cc5565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610de5575b5050610cba565b610dee90613135565b6104a0578338610dde565b50803b1515610cb5565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c65565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ea68a6139bd565b15610bcd565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae576040826001600160a01b03926020945260098452205416604051908152f35b503461063a57602036600319011261063a5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063a57608036600319011261063a576110186130a3565b6110206130b9565b906064359067ffffffffffffffff82116104a057366023830112156104a0578160040135928461104f856131fa565b9361105d60405195866131d8565b8585523660248783010111610a55578561108896602460209301838801378501015260443591613551565b80f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761111590613799565b60405190600581101561112a57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063a5761014036600319011261063a57611159613961565b6111616134ea565b9064ffffffffff8042168084528161117761353d565b16611272575b60e43590828216820361126d5701166040830152600435916001600160a01b039182841680940361126d576024359083821680920361126d57604435906001600160801b03821680920361126d576064359085821680920361063a57506084359182151580930361126d5760a4359384151580950361126d576040519761120389613149565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126d576040519161123d836131bc565b61010435918216820361126d57826112659260209452610124358482015260e0820152613aa4565b604051908152f35b600080fd5b8161127b61353d565b820116602085015261117d565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760026040836001600160801b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a576112f46130a3565b6024359081151580920361126d576001600160a01b03169081156113665733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a578060031936011261063a5760405190806002549160018360011c926001851694851561149c575b60209586861081146114885785885287949392918790821561146657505060011461140c575b50506113f8925003836131d8565b6109d460405192828493845283019061307e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144e5750506113f8935082010138806113ea565b80548389018501528794508693909201918101611436565b92509350506113f894915060ff191682840152151560051b82010138806113ea565b602483634e487b7160e01b81526022600452fd5b93607f16936113c4565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761152f90613799565b90600582101590816115705760028314918215611584575b821561155b575b6020836040519015158152f35b9091506115705750600460209114388061154e565b80634e487b7160e01b602492526021600452fd5b506003831491506000611547565b503461063a57602036600319011261063a57806101606040516115b481613182565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f76134ea565b61014082015201526004358152600960205260ff600160408320015460a81c161561189a576004358152600960205260408120906116c560026040519361163d8561319f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613509565b6101208301526116d6600435613799565b6005811015611886576101606101c093600264ffffffffff931461187b575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117828d613182565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f5565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063a57602080600319360112610a555760043567ffffffffffffffff811161049c576118e5903690600401613104565b91906118ef613961565b83925b8084106118fd578480f35b6119088482846134c4565b3593611912613961565b848652600980855260ff600191818360408b20015460a81c1615611bed57878952808752604089208381015460a01c8316156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd5576119918160005260096020526001600160a01b0360406000205416331490565b15611bb55761199f816136e1565b93818a528289526119b5600260408c2001613509565b946001600160801b0394858751168683161015611b9d57838c52848b5260408c205460f01c1615611b8557918493918a611a0185878f9a99808c9986928d511603169a01511690613250565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611ad160408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611b6c575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aa98b8588614170565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b15575b5050505050506001019291906118f2565b813b15610d7557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b58575b80808080611b04565b611b6190613135565b610524578438611b4f565b818601600160a01b60ff60a01b19825416179055611a68565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a555760043590611c23613961565b8183526009815260ff600160408520015460a81c1615611e1457611c4682613799565b6005811015611e005760048103611c6f5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8f576024836040519063fe19f19f60e01b82526004820152fd5b600214611de857611cb68260005260096020526001600160a01b0360406000205416331490565b15611dc9578183526009815260ff604084205460f01c1615611db157818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d59575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9d575b80611d2a565b611da690613135565b61049c578238611d97565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a576004356001600160a01b039081811680910361049c5781835416338103611efc575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee85760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063a57602036600319011261063a57611f8c6130a3565b9080546001600160a01b0380821693338503611fde576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461063a57602036600319011261063a576001600160a01b036120276130a3565b168015612044578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57602036600319011261063a5760206120946004356136be565b6001600160a01b0360405191168152f35b503461063a5761016036600319011261063a576120c0613961565b604051906120cd82613149565b6120d56130a3565b82526120df6130b9565b60208301526120ec613216565b60408301526001600160a01b03906064358281168103610a55576060840152608435801515810361126d57608084015260a435801515810361126d5760a084015260603660c319011261063a575060405161214681613166565b64ffffffffff60c435818116810361126d57825260e435818116810361126d57602083015261010435908116810361126d57604082015260c083015260406101231936011261126d576040519161219c836131bc565b61012435918216820361126d57826112659260209452610144358482015260e0820152613aa4565b503461063a57604036600319011261063a5767ffffffffffffffff60043581811161049c576121f7903690600401613104565b90916024359081116104a057612211903690600401613104565b612219613961565b80830361263557845b83811061222d578580f35b6122388185876134c4565b35906122458186886134c4565b35875260036020526001600160a01b036040882054166122668285876134c4565b35906001600160801b038216820361126d57612280613961565b838952600960205260ff600160408b20015460a81c161561062357838952600960205260ff600160408b20015460a01c1661060b57801561261d576001600160801b038216156126055783895260036020526001600160a01b0360408a2054169182821415806125f5575b6125d1576122f885614148565b6001600160801b0381166001600160801b038316116125a15750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123898c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ad8160208401511692826040818351169201511690613250565b161115612570575b86855260096020526001600160a01b036001604087200154166123e26001600160801b0384168583614170565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612566575b6124fc575b8333141590816124f1575b816124e6575b50612474575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612222565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124ce575b808061243d565b6124d790613135565b6124e25786386124c7565b8680fd5b905083141538612437565b843b15159150612431565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612552575b5050612426565b61255b90613135565b61052457843861254b565b50803b1515612421565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b5565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125ff856139bd565b156122eb565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091613a26565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1457806126e283613799565b92600584101561188657600260209403612703575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126f7565b503461063a578060031936011261063a5760206001600160a01b0360085416604051908152f35b503461063a57602080600319360112610a555760043590612763613961565b8183526009815260ff600160408520015460a81c1615611e14578183526009815260ff600160408520015460a01c16156128ea576127a0826139bd565b15611dc95781600052600381526001600160a01b0380604060002054161515806128e2575b806128c8575b6128b0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612875575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161285d575080f35b60249060405190637e27328960e01b82526004820152fd5b61289685600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561280b565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c16156127cb565b5060006127c5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a5761292a366130cf565b60405191602083019383851067ffffffffffffffff8611176129555761108894604052858452613551565b634e487b7160e01b600052604160045260246000fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063a576020908160031936011261063a57600435906129dc613961565b818152600980845260ff600160408420015460a81c16156109325782825280845260408220600181015460a01c60ff1615612a295760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612c3757612a548260005260096020526001600160a01b0360406000205416331490565b15611dc957612a62826136e1565b93828452818152612a7860026040862001613509565b926001600160801b0391828551168388161015611de85781865283815260ff604087205460f01c1615611db1577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612ae1888584818b9c818c9d9c511603169a01511690613250565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612c1d575b01896001600160801b03198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612b898d8487614170565b8c612bb86040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612bcc578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c0e575b81818080808480f35b612c1790613135565b38612c05565b60018101600160a01b60ff60a01b19825416179055612b25565b6024826040519063fe19f19f60e01b82526004820152fd5b503461063a57611088612c61366130cf565b9161327f565b503461063a578060031936011261063a576020600754604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57612cbe90613799565b9060058210156115705760208215838115612cdf575b506040519015158152f35b600191501482612cd4565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1457602091604082828152600985522060ff815460f01c1680612d78575b612d4f575b50506001600160801b0360405191168152f35b612d7192506001600160801b036002612d6b92015416916136e1565b90613250565b3880612d3c565b5060ff600182015460a01c1615612d37565b503461063a57604036600319011261063a57612da46130a3565b602435612db0816136be565b33151580612e70575b80612e46575b612e165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612dbf565b50336001600160a01b0382161415612db9565b503461063a57602036600319011261063a57602061209460043561322c565b503461063a578060031936011261063a576040519080600191600154928360011c9260018516948515612f5d575b602095868610811461148857858852879493929187908215611466575050600114612f035750506113f8925003836131d8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f455750506113f8935082010138806113ea565b80548389018501528794508693909201918101612f2d565b93607f1693612ed0565b503461063a578060031936011261063a57602060405167016345785d8a00008152f35b905034610a55576020366003190112610a55576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613031575b8115613007575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613000565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612ff9565b60005b83811061306e5750506000910152565b818101518382015260200161305e565b906020916130978151809281855285808601910161305b565b601f01601f1916010190565b600435906001600160a01b038216820361126d57565b602435906001600160a01b038216820361126d57565b606090600319011261126d576001600160a01b0390600435828116810361126d5791602435908116810361126d579060443590565b9181601f8401121561126d5782359167ffffffffffffffff831161126d576020808501948460051b01011161126d57565b67ffffffffffffffff811161295557604052565b610100810190811067ffffffffffffffff82111761295557604052565b6060810190811067ffffffffffffffff82111761295557604052565b610180810190811067ffffffffffffffff82111761295557604052565b610140810190811067ffffffffffffffff82111761295557604052565b6040810190811067ffffffffffffffff82111761295557604052565b90601f8019910116810190811067ffffffffffffffff82111761295557604052565b67ffffffffffffffff811161295557601f01601f191660200190565b604435906001600160801b038216820361126d57565b613235816136be565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161326957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156134ac57600091848352602091600383526040928284862054161515806134a4575b8061348c575b6134755786855260038152828486205416948733151593846133c5575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761338d575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361335f5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133ae82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132fb565b91929380915090613434575b156133df57908783926132d2565b8488876133fc576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613459575b806133d157508782526005835233848684205416146133d1565b5085825260068352848220338352835260ff858320541661343f565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c16156132b5565b5060016132af565b6024604051633250574960e11b815260006004820152fd5b91908110156134d45760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134f782613166565b60006040838281528260208201520152565b9060405161351681613166565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361126d5790565b919061355e82828561327f565b803b61356b575b50505050565b6135c76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061307e565b03906020816000938185885af19082908261365d575b505061361457826135ec614118565b805191908261360d5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613645575038808080613565565b60249060405190633250574960e11b82526004820152fd5b909192506020813d6020116136b6575b8161367a602093836131d8565b81010312610a555751907fffffffff000000000000000000000000000000000000000000000000000000008216820361063a57509038806135dd565b3d915061366d565b8060005260036020526001600160a01b036040600020541690811561285d575090565b600090808252600a60205264ffffffffff918260408220541642106137935760096020526040812092835490808260c81c16918242101561377d576137329394955060a01c16809103904203614314565b9082815260096020526001600160801b03926137588460026040852001541680946143f4565b9283116137655750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c166000146137c0575050600490565b805460f81c613819575460a01c64ffffffffff164210613813576137e3816136e1565b9060005260096020526001600160801b03806002604060002001541691161060001461380e57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613956575b8061393e575b613927579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138ef575b1692836138d9575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138b5565b61391086600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138ad565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561384c565b508181161515613846565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361399357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415613a02575b505082156139f057505090565b9091506139fd339261322c565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139e3565b806000526009602052613a3f6002604060002001613509565b816000526009602052604060002060ff600182015460a01c16600014613a7257506001600160801b039150602001511690565b5460f81c613a875750613a84906136e1565b90565b613a8491506001600160801b036040818351169201511690613250565b90613ac56001600160801b03604084015116602060e08501510151906141cc565b916001600160801b0383511660c082015190156140ee5764ffffffffff815116156140c4576020810164ffffffffff81511680614014575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fd457505064ffffffffff8042169151169081811015613f94575050600754926001600160801b0381511660405190613b5482613166565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb68861319f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dae84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f76575b50600184016007556001600160a01b0360208301511680156134ac57613dfe856001600160a01b0392613820565b16613f4557613e296001600160a01b036060840151166001600160801b0383511690309033906142a5565b6001600160801b0360208201511680613f16575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0d6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3f906001600160a01b036060850151166001600160a01b0360e086015151169033906142a5565b38613e3d565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dd0565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561408457505064ffffffffff90511664ffffffffff60408301511690818110613afd576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614143573d90614129826131fa565b9161413760405193846131d8565b82523d6000602084013e565b606090565b613a849061415581613a26565b90600052600960205260026040600020015460801c90613250565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ca916141c56064836131d8565b6144a3565b565b919091604051906141dc826131bc565b600091828152826020820152936001600160801b03928383169182156142865767016345785d8a000080821161424f57506142188591846143f4565b166020870192818452111561423b5750908261423692511690613250565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061429a826131bc565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612955576141ca926040526144a3565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143d0578285101561439457908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143de570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461449257670de0b6b3a7640000908183101561445b57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144ce600080836020829551910182875af16144c7614118565b908461453f565b908151918215159283614517575b5050506144e65750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a5557602001519081159182150361063a57503880806144dc565b9061457e575080511561455457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145c9575b61458f575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561458756fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004e243881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a22908162000402823960805181613e04015260a051818181612f190152613eaa0152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461327757508063027b67441461325457806306fdde031461318f578063081812fc14613170578063095ea7b3146130775780631400ecec14612fd75780631c1cdd4c14612f725780631e99d56914612f5457806323b872dd14612f3c5780632fe4304114612f0157806332fbe22b14612da957806340e58ee514612b0b578063425d30dd14612aba57806342842e0e14612a8057806342966c68146128a957806344267570146128825780634857501f1461280c5780634869e12d146127d15780634cc55e111461230e5780636352211e146122de5780636d0cee75146122de57806370a082311461226e57806375829def146121db5780637cad6cd1146120e15780637de6b1db14611eba5780637f5799f914611e5f5780638659c27014611b05578063894e9a0d14611779578063897f362b146114c95780638f69b9931461142d5780639067b677146113dd57806395d89b41146112ce578063a22cb46514611211578063a80fc071146111bf578063ad35efd41461115d578063b25645691461110c578063b88d4fde1461107f578063b8a3be661461104a578063b971302a14610ffb578063bc2be1be14610fab578063c156a11d14610afc578063c87b56dd146109e0578063cc364f4814610948578063d4dbd20b146108f6578063d511609f146108aa578063d975dfed1461085e578063e985e9c514610809578063ea5ead191461070f578063eac8f5b8146106bd578063f590c1761461065b578063f851a440146106355763fdd46d601461025d57600080fd5b34610632576060366003190112610632576004359061027a6133a6565b91604435926001600160801b038085169182860361062d5761029a613dfa565b83855260099560209387855260ff600160408920015460a81c16156106165785875287855260ff600160408920015460a01c166105fe576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f89614655565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c906103439161467d565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561037990613949565b908084830151169181808251169160400151166103959161358e565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886147e2565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b610498906134af565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b610520906134af565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c88961453e565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106325780600319360112610632576001600160a01b036020915416604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576004359061072d6133a6565b9161073781614655565b92610740613dfa565b81835260099360209185835260ff600160408720015460a81c16156107f25783855285835260ff600160408720015460a01c166107da576001600160a01b03918282169283156107c2576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f89614655565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b503461063257604036600319011261063257610823613390565b604061082d6133a6565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a657610899602091614655565b6001600160801b0360405191168152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082600292602094526009845220015460801c604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760036040836001600160801b0393602095526009855220015416604051908152f35b5034610632576020366003190112610632576004356000602060405161096d816134fc565b8281520152808252600960205260ff600160408420015460a81c16156106a657604082819281526009602052205464ffffffffff8251916109ad836134fc565b818160a01c16835260c81c1660208201526109de825180926020908164ffffffffff91828151168552015116910152565bf35b503461063257602080600319360112610aec576004356109ff81613b0b565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610af0578093610a6f575b5050610a6b60405192828493845283019061336b565b0390f35b909192503d8082843e610a828184613518565b8201918381840312610aec5780519067ffffffffffffffff82116104a3570182601f82011215610aec57805191610ab88361353a565b93610ac66040519586613518565b838552858484010111610632575090610ae491848085019101613348565b903880610a55565b5080fd5b604051903d90823e3d90fd5b503461063257604036600319011261063257600435610b196133a6565b610b21613dfa565b81835260099060209082825260ff600160408720015460a81c16156107f257838552600382526001600160a01b03918260408720541693843303610f8c57610b6886614655565b906001600160801b039081831680158015610c08575b50505050505081811615610bf05783610b9691613cb9565b90811680610bb65760248460405190637e27328960e01b82526004820152fd5b8203610bc0578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c10613dfa565b898b5282865260ff600160408d20015460a81c1615610f7557898b5282865260ff600160408d20015460a01c16610f5d578815610f4557610f2d57888a52600385528660408b205416918289141580610f1d575b610ef957610c718a614655565b8481168311610ec75750908a949392918a86528087526040862093610cd6610ca48760028d89541698015460801c61467d565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155613949565b90610cf2818a840151169282604081835116920151169061358e565b161115610e98575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d398186886147e2565b604051908152a48033141580610e8e575b610e24575b813314159081610e19575b81610e0e575b50610d9d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b7e565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df6575b80610d66565b610dff906134af565b610e0a578538610df0565b8580fd5b905081141538610d60565b823b15159150610d5a565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e7a575b5050610d4f565b610e83906134af565b6104a7578338610e73565b50803b1515610d4a565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cfa565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f278a61453e565b15610c64565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576040826001600160a01b03926020945260098452205416604051908152f35b50346106325760203660031901126106325760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063257608036600319011261063257611099613390565b6110a16133a6565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110d08561353a565b936110de6040519586613518565b8585523660248783010111610aec57856111099660246020930183880137850101526044359161399e565b80f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761119690613c32565b6040519060058110156111ab57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760026040836001600160801b0393602095526009855220015416604051908152f35b50346106325760403660031901126106325761122b613390565b6024359081151580920361062d576001600160a01b031690811561129d5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257806003193601126106325760405190806002549160018360011c92600185169485156113d3575b60209586861081146113bf5785885287949392918790821561139d575050600114611343575b505061132f92500383613518565b610a6b60405192828493845283019061336b565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061138557505061132f93508201013880611321565b8054838901850152879450869390920191810161136d565b925093505061132f94915060ff191682840152151560051b8201013880611321565b602483634e487b7160e01b81526022600452fd5b93607f16936112fb565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761146690613c32565b90600582101590816114a757600283149182156114bb575b8215611492575b6020836040519015158152f35b9091506114a757506004602091143880611485565b80634e487b7160e01b602492526021600452fd5b50600383149150600061147e565b5034610632576020906003198281360112610aec576004359167ffffffffffffffff91828411610aec5761012084360391820112610aec57611509613dfa565b60c48401359060221901811215610aec5783016004810135928311610aec5760248101908360061b80360383136104a75760249061154686613814565b956115546040519788613518565b8652878601920101913683116104a757905b86838310611761575050505081519061157e82613814565b9261158c6040519485613518565b828452601f1961159b84613814565b0186835b82811061173d5750505064ffffffffff804216936001600160801b0392836115c682613b2e565b51511683808b6115d585613b2e565b51015116880116604051916115e9836134fc565b82528a8201526115f888613b2e565b5261160287613b2e565b5060019260015b8381106116d45750505050506116218560040161397d565b9161162e6024870161397d565b9161163b604488016138b7565b6064880135926001600160a01b039081851680950361063257509288959261168c9895926116c1989561167360846116cc9d01613991565b948161168160a48c01613991565b976040519d8e613492565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613862565b610100820152613e56565b604051908152f35b8089838d8180826116f98d6116ea8e9a8d613b3b565b51511696600019890190613b3b565b5101511691611708868a613b3b565b5101511601166040519161171b836134fc565b82528d82015261172b828c613b3b565b52611736818b613b3b565b5001611609565b604051611749816134fc565b6000815260008382015282828901015201879061159f565b60409161176e368561382c565b815201910190611566565b503461063257602036600319011261063257606061016060405161179c816134c3565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117e2816134e0565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611aed5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ad7576118d39160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613949565b6101208301526118e4600435613c32565b6005811015611ac3576101609261198f9260026119cb9314611ab8575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e6134c3565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138cb565b82820152610a6b604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e0830190613436565b806060830152611901565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063257602080600319360112610aec5760043567ffffffffffffffff81116104a357611b38903690600401613405565b9190611b42613dfa565b83925b808410611b50578480f35b611b5b848284613891565b3593611b65613dfa565b848652600980855260ff90600190828260408b20015460a81c1615611e4857878952808752604089208281015460a01c841615611bb45760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e3057611be58160005260096020526001600160a01b0360406000205416331490565b15611e1057611bf381613b4f565b818a52828952611c08600260408c2001613949565b906001600160801b0395868351168783161015611df857838c52848b5260408c205460f01c1615611de05791818a611c5985898f9a999896611c4f8c99838793511661358e565b950151169061358e565b8386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5060408720916040835499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161785558b83169a8b15611dc7575b60038096019c88169c8d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611d0c8b85886147e2565b604080518881526001600160801b0392831660208201529290911690820152606090a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d70575b505050505050600101929190611b45565b813b15610e0a57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611db3575b80808080611d5f565b611dbc906134af565b61052b578438611daa565b818601600160a01b60ff60a01b19825416179055611cbe565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082611ea692610a6b9452600a602052206138cb565b604051918291602083526020830190613436565b503461063257602080600319360112610aec5760043590611ed9613dfa565b8183526009815260ff600160408520015460a81c16156120ca57611efc82613c32565b60058110156120b65760048103611f255760248360405190634a5541ef60e01b82526004820152fd5b60038103611f45576024836040519063fe19f19f60e01b82526004820152fd5b60021461209e57611f6c8260005260096020526001600160a01b0360406000205416331490565b1561207f578183526009815260ff604084205460f01c161561206757818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b61200f575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612053575b80611fe0565b61205c906134af565b6104a357823861204d565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610632576020366003190112610632576004356001600160a01b03908181168091036104a357818354163381036121b2575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161219e5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610632576020366003190112610632576121f5613390565b9080546001600160a01b0380821693338503612247576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610632576020366003190112610632576001600160a01b03612290613390565b1680156122ad578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106325760203660031901126106325760206122fd600435613b0b565b6001600160a01b0360405191168152f35b50346106325760403660031901126106325767ffffffffffffffff6004358181116104a357612341903690600401613405565b9091602490813590811161052b5761235d903690600401613405565b612368929192613dfa565b80840361279b57855b84811061237c578680f35b612387818688613891565b3590612394818789613891565b35885260036020526001600160a01b036040892054166123bd6123b8838689613891565b6138b7565b906123c6613dfa565b838a52600960205260ff600160408c20015460a81c161561278557838a52600960205260ff600160408c20015460a01c1661276e578015612757576001600160801b0382161561274057838a5260036020526001600160a01b0360408b205416918282141580612730575b61270c5761243e85614655565b6001600160801b0381166001600160801b038316116126dc5750908a9291858452600960205260408420926124c46001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff196124a687608094851c61467d565b938c8b52600960205260408b2001938454931b169116178155613949565b6001600160801b036124e8816020840151169282604081835116920151169061358e565b1611156126ab575b86855260096020526001600160a01b0360016040872001541661251d6001600160801b03841685836147e2565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126a1575b612637575b83331415908161262c575b81612621575b506125af575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612371565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1612609575b8080612578565b612612906134af565b61261d578738612602565b8780fd5b905083141538612572565b843b1515915061256c565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161268d575b5050612561565b612696906134af565b61052b578438612686565b50803b151561255c565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124f0565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061273a8561453e565b15612431565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a6576108996020916145a7565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120ca578061284783613c32565b926005841015611ac357600260209403612868575b50506040519015158152f35b815260098352604090205460f01c60ff169050388061285c565b503461063257806003193601126106325760206001600160a01b0360085416604051908152f35b503461063257602080600319360112610aec57600435906128c8613dfa565b8183526009815260ff600160408520015460a81c16156120ca578183526009815260ff600160408520015460a01c1615612a4f576129058261453e565b1561207f5781600052600381526001600160a01b038060406000205416151580612a47575b80612a2d575b612a15577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260038352604060002054169182159283156129da575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129c2575080f35b60249060405190637e27328960e01b82526004820152fd5b6129fb85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612970565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615612930565b50600061292a565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257612a8f366133d0565b60405191602083019383851067ffffffffffffffff861117611ad7576111099460405285845261399e565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063257602090816003193601126106325760043590612b2b613dfa565b81815260099283815260ff600160408420015460a81c1615612d925782825283815260408220600181015460a01c60ff1615612b795760248460405190634a5541ef60e01b82526004820152fd5b9284935460f81c611e3057612ba48160005260096020526001600160a01b0360406000205416331490565b15611e1057612bb281613b4f565b93818452808352612bc860026040862001613949565b916001600160801b039384845116858816101561209e5781865282815260ff604087205460f01c161561206757612c16878683612c0c8a9b838a9c9b9c511661358e565b970151169061358e565b908286528381526040862091825494600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87161784556003898316948515612d78575b01988716988981546fffffffffffffffffffffffffffffffff19161790556001600160a01b038096168097600385528760408b205416978893865260408b20600101541693612cab8c84876147e2565b604080518981526001600160801b03938416602082015292909116908201528060608101037f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5091a4604051908382527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791a1823b612d27578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d69575b81818080808480f35b612d72906134af565b81612d60565b60018101600160a01b60ff60a01b19825416179055612c5b565b6024836040519062b8e7e760e51b82526004820152fd5b5034610632576003199060203683018113610aec576004359167ffffffffffffffff93848411610aec5761014090843603011261063257612de8613dfa565b60405193612df585613492565b612e01846004016133bc565b8552612e0f602485016133bc565b6020860152612e2060448501613556565b604086015260648401356001600160a01b03811681036104a3576060860152612e4b60848501613485565b6080860152612e5c60a48501613485565b60a0860152612e6d60c48501613802565b60c086015260e4840135908111610aec5783019136602384011215610aec576004830135612e9a81613814565b93612ea86040519586613518565b8185526024602086019260061b820101933685116106325750602401905b838210612ee85760206116cc886116c1898960e0840152610104369101613862565b82604091612ef6368561382c565b815201910190612ec6565b503461063257806003193601126106325760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461063257611109612f4e366133d0565b916135bd565b50346106325780600319360112610632576020600754604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657612fab90613c32565b9060058210156114a75760208215838115612fcc575b506040519015158152f35b600191501482612fc1565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120ca57602091604082828152600985522060ff815460f01c1680613065575b61303c575b50506001600160801b0360405191168152f35b61305e92506001600160801b0360026130589201541691613b4f565b9061358e565b3880613029565b5060ff600182015460a01c1615613024565b503461063257604036600319011261063257613091613390565b60243561309d81613b0b565b3315158061315d575b80613133575b6131035781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff604085205416156130ac565b50336001600160a01b03821614156130a6565b50346106325760203660031901126106325760206122fd60043561356a565b50346106325780600319360112610632576040519080600191600154928360011c926001851694851561324a575b60209586861081146113bf5785885287949392918790821561139d5750506001146131f057505061132f92500383613518565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061323257505061132f93508201013880611321565b8054838901850152879450869390920191810161321a565b93607f16936131bd565b5034610632578060031936011261063257602060405167016345785d8a00008152f35b905034610aec576020366003190112610aec576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd00000000000000000000000000000000000000000000000000000000811490811561331e575b81156132f4575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014386132ed565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506132e6565b60005b83811061335b5750506000910152565b818101518382015260200161334b565b9060209161338481518092818552858086019101613348565b601f01601f1916010190565b600435906001600160a01b038216820361062d57565b602435906001600160a01b038216820361062d57565b35906001600160a01b038216820361062d57565b606090600319011261062d576001600160a01b0390600435828116810361062d5791602435908116810361062d579060443590565b9181601f8401121561062d5782359167ffffffffffffffff831161062d576020808501948460051b01011161062d57565b90815180825260208080930193019160005b828110613456575050505090565b835180516001600160801b0316865282015164ffffffffff168583015260409094019392810192600101613448565b3590811515820361062d57565b610120810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757604052565b610180810190811067ffffffffffffffff821117611ad757604052565b6060810190811067ffffffffffffffff821117611ad757604052565b6040810190811067ffffffffffffffff821117611ad757604052565b90601f8019910116810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757601f01601f191660200190565b35906001600160801b038216820361062d57565b61357381613b0b565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116135a757565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156137ea57600091848352602091600383526040928284862054161515806137e2575b806137ca575b6137b3578685526003815282848620541694873315159384613703575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876136cb575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361369d5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6136ec82600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055613639565b91929380915090613772575b1561371d5790878392613610565b84888761373a576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613797575b8061370f575087825260058352338486842054161461370f565b5085825260068352848220338352835260ff858320541661377d565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c16156135f3565b5060016135ed565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361062d57565b67ffffffffffffffff8111611ad75760051b60200190565b919082604091031261062d57604051613844816134fc565b602061385d81839561385581613556565b855201613802565b910152565b919082604091031261062d5760405161387a816134fc565b6020808294613888816133bc565b84520135910152565b91908110156138a15760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361062d5790565b9081546138d781613814565b926040936138e86040519182613518565b82815280946020809201926000526020600020906000935b85851061390f57505050505050565b6001848192845161391f816134fc565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613900565b90604051613956816134e0565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062d5790565b35801515810361062d5790565b91906139ab8282856135bd565b803b6139b8575b50505050565b613a146001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061336b565b03906020816000938185885af190829082613aaa575b5050613a615782613a39614625565b8051919082613a5a5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613a925750388080806139b2565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613b03575b81613ac760209383613518565b81010312610aec5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106325750903880613a2a565b3d9150613aba565b8060005260036020526001600160a01b03604060002054169081156129c2575090565b8051156138a15760200190565b80518210156138a15760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b7260406000206138cb565b9084846020613b8085613b2e565b5101511611613c2857600052600960205260406000208484825460c81c161115613c1357506001600160801b039081613bb882613b2e565b515116946001948594855b613bd2575b5050505050505090565b8351871015613c0e57828282613be88a88613b3b565b5101511611613c0e578585889981613c01849b89613b3b565b5151160116980196613bc3565b613bc8565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613c59575050600490565b805460f81c613cb2575460a01c64ffffffffff164210613cac57613c7c81613b4f565b9060005260096020526001600160801b038060026040600020015416911610600014613ca757600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613def575b80613dd7575b613dc0579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d88575b169283613d72575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d4e565b613da986600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d46565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613ce5565b508181161515613cdf565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e2c57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e786001600160801b036040840151166020610100850151015190614698565b6001600160801b0381511660e084015164ffffffffff60c08601511682156145145780156144ea57815180156144c0577f0000000000000000000000000000000000000000000000000000000000000000811161448f575064ffffffffff6020613ee184613b2e565b510151168110156144385750600090819082815184905b8082106143a7575050505064ffffffffff421664ffffffffff82168110156143675750506001600160801b0316808203614330575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140948951996000198b0190613b3b565b51015160c81b169560f01b16911617171717845560005b81811061428b575050600185016007556001600160a01b0360208301511680156137ea576140e1866001600160a01b0392613cb9565b1661425a5761410c6001600160a01b036060840151166001600160801b038351169030903390614771565b6001600160801b036020820151168061422a575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661421f61420060808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a98c6134fc565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c0880152860190613436565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b614254906001600160a01b036060850151166001600160a01b036101008601515116903390614771565b38614120565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142a88160e0870151613b3b565b51825468010000000000000000811015611ad757600181018085558110156138a157600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140ab565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143cb906001600160801b036143c28588613b3b565b5151169061467d565b9364ffffffffff8060206143df8685613b3b565b510151169416808511156143fb57506001849301909291613ef8565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061444984613b2e565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614583575b5050821561457157505090565b90915061457e339261356a565b161490565b60ff9294509060409181526006602052818120338252602052205416913880614564565b8060005260096020526145c06002604060002001613949565b816000526009602052604060002060ff600182015460a01c166000146145f357506001600160801b039150602001511690565b5460f81c614608575061460590613b4f565b90565b61460591506001600160801b03604081835116920151169061358e565b3d15614650573d906146368261353a565b916146446040519384613518565b82523d6000602084013e565b606090565b61460590614662816145a7565b90600052600960205260026040600020015460801c9061358e565b9190916001600160801b03808094169116019182116135a757565b919091604051906146a8826134fc565b600091828152826020820152936001600160801b03928383169182156147525767016345785d8a000080821161471b57506146e48591846148d3565b1660208701928184521115614707575090826147029251169061358e565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5093945050505060405190614766826134fc565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ad7576147e092604052614837565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147e091614837606483613518565b6001600160a01b031690614862600080836020829551910182875af161485b614625565b9084614982565b9081519182151592836148ab575b50505061487a5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610aec5760200151908115918215036106325750388080614870565b9091906000198382098382029182808310920391808303921461497157670de0b6b3a7640000908183101561493a57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149c1575080511561499757805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614a0c575b6149d2575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149ca56fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004e3a3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a38908162000402823960805181613e1a015260a051818181612f2f0152613ec00152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461328d57508063027b67441461326a57806306fdde03146131a5578063081812fc14613186578063095ea7b31461308d5780631400ecec14612fed5780631c1cdd4c14612f885780631e99d56914612f6a57806323b872dd14612f525780632fe4304114612f1757806332fbe22b14612dbf57806340e58ee514612b0c578063425d30dd14612abb57806342842e0e14612a8157806342966c68146128aa57806344267570146128835780634857501f1461280d5780634869e12d146127d25780634cc55e111461230f5780636352211e146122df5780636d0cee75146122df57806370a082311461226f57806375829def146121dc5780637cad6cd1146120e25780637de6b1db14611ebb5780637f5799f914611e605780638659c27014611b05578063894e9a0d14611779578063897f362b146114c95780638f69b9931461142d5780639067b677146113dd57806395d89b41146112ce578063a22cb46514611211578063a80fc071146111bf578063ad35efd41461115d578063b25645691461110c578063b88d4fde1461107f578063b8a3be661461104a578063b971302a14610ffb578063bc2be1be14610fab578063c156a11d14610afc578063c87b56dd146109e0578063cc364f4814610948578063d4dbd20b146108f6578063d511609f146108aa578063d975dfed1461085e578063e985e9c514610809578063ea5ead191461070f578063eac8f5b8146106bd578063f590c1761461065b578063f851a440146106355763fdd46d601461025d57600080fd5b34610632576060366003190112610632576004359061027a6133bc565b91604435926001600160801b038085169182860361062d5761029a613e10565b83855260099560209387855260ff600160408920015460a81c16156106165785875287855260ff600160408920015460a01c166105fe576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961466b565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614693565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556103799061395f565b90808483015116918180825116916040015116610395916135a4565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886147f8565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b610498906134c5565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b610520906134c5565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614554565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106325780600319360112610632576001600160a01b036020915416604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576004359061072d6133bc565b916107378161466b565b92610740613e10565b81835260099360209185835260ff600160408720015460a81c16156107f25783855285835260ff600160408720015460a01c166107da576001600160a01b03918282169283156107c2576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961466b565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b5034610632576040366003190112610632576108236133a6565b604061082d6133bc565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a65761089960209161466b565b6001600160801b0360405191168152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082600292602094526009845220015460801c604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760036040836001600160801b0393602095526009855220015416604051908152f35b5034610632576020366003190112610632576004356000602060405161096d81613512565b8281520152808252600960205260ff600160408420015460a81c16156106a657604082819281526009602052205464ffffffffff8251916109ad83613512565b818160a01c16835260c81c1660208201526109de825180926020908164ffffffffff91828151168552015116910152565bf35b503461063257602080600319360112610aec576004356109ff81613b21565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610af0578093610a6f575b5050610a6b604051928284938452830190613381565b0390f35b909192503d8082843e610a82818461352e565b8201918381840312610aec5780519067ffffffffffffffff82116104a3570182601f82011215610aec57805191610ab883613550565b93610ac6604051958661352e565b838552858484010111610632575090610ae49184808501910161335e565b903880610a55565b5080fd5b604051903d90823e3d90fd5b503461063257604036600319011261063257600435610b196133bc565b610b21613e10565b81835260099060209082825260ff600160408720015460a81c16156107f257838552600382526001600160a01b03918260408720541693843303610f8c57610b688661466b565b906001600160801b039081831680158015610c08575b50505050505081811615610bf05783610b9691613ccf565b90811680610bb65760248460405190637e27328960e01b82526004820152fd5b8203610bc0578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c10613e10565b898b5282865260ff600160408d20015460a81c1615610f7557898b5282865260ff600160408d20015460a01c16610f5d578815610f4557610f2d57888a52600385528660408b205416918289141580610f1d575b610ef957610c718a61466b565b8481168311610ec75750908a949392918a86528087526040862093610cd6610ca48760028d89541698015460801c614693565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b16911617815561395f565b90610cf2818a84015116928260408183511692015116906135a4565b161115610e98575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d398186886147f8565b604051908152a48033141580610e8e575b610e24575b813314159081610e19575b81610e0e575b50610d9d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b7e565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df6575b80610d66565b610dff906134c5565b610e0a578538610df0565b8580fd5b905081141538610d60565b823b15159150610d5a565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e7a575b5050610d4f565b610e83906134c5565b6104a7578338610e73565b50803b1515610d4a565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cfa565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f278a614554565b15610c64565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576040826001600160a01b03926020945260098452205416604051908152f35b50346106325760203660031901126106325760ff6001604060209360043581526009855220015460a81c166040519015158152f35b5034610632576080366003190112610632576110996133a6565b6110a16133bc565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110d085613550565b936110de604051958661352e565b8585523660248783010111610aec5785611109966024602093018388013785010152604435916139b4565b80f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761119690613c48565b6040519060058110156111ab57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760026040836001600160801b0393602095526009855220015416604051908152f35b50346106325760403660031901126106325761122b6133a6565b6024359081151580920361062d576001600160a01b031690811561129d5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257806003193601126106325760405190806002549160018360011c92600185169485156113d3575b60209586861081146113bf5785885287949392918790821561139d575050600114611343575b505061132f9250038361352e565b610a6b604051928284938452830190613381565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061138557505061132f93508201013880611321565b8054838901850152879450869390920191810161136d565b925093505061132f94915060ff191682840152151560051b8201013880611321565b602483634e487b7160e01b81526022600452fd5b93607f16936112fb565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761146690613c48565b90600582101590816114a757600283149182156114bb575b8215611492575b6020836040519015158152f35b9091506114a757506004602091143880611485565b80634e487b7160e01b602492526021600452fd5b50600383149150600061147e565b5034610632576020906003198281360112610aec576004359167ffffffffffffffff91828411610aec5761012084360391820112610aec57611509613e10565b60c48401359060221901811215610aec5783016004810135928311610aec5760248101908360061b80360383136104a7576024906115468661382a565b95611554604051978861352e565b8652878601920101913683116104a757905b86838310611761575050505081519061157e8261382a565b9261158c604051948561352e565b828452601f1961159b8461382a565b0186835b82811061173d5750505064ffffffffff804216936001600160801b0392836115c682613b44565b51511683808b6115d585613b44565b51015116880116604051916115e983613512565b82528a8201526115f888613b44565b5261160287613b44565b5060019260015b8381106116d457505050505061162185600401613993565b9161162e60248701613993565b9161163b604488016138cd565b6064880135926001600160a01b039081851680950361063257509288959261168c9895926116c1989561167360846116cc9d016139a7565b948161168160a48c016139a7565b976040519d8e6134a8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613878565b610100820152613e6c565b604051908152f35b8089838d8180826116f98d6116ea8e9a8d613b51565b51511696600019890190613b51565b5101511691611708868a613b51565b5101511601166040519161171b83613512565b82528d82015261172b828c613b51565b52611736818b613b51565b5001611609565b60405161174981613512565b6000815260008382015282828901015201879061159f565b60409161176e3685613842565b815201910190611566565b503461063257602036600319011261063257606061016060405161179c816134d9565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117e2816134f6565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611aed5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ad7576118d39160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161395f565b6101208301526118e4600435613c48565b6005811015611ac3576101609261198f9260026119cb9314611ab8575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e6134d9565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138e1565b82820152610a6b604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061344c565b806060830152611901565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063257602080600319360112610aec5760043567ffffffffffffffff81116104a357611b3890369060040161341b565b9190611b42613e10565b83925b808410611b50578480f35b611b5b8482846138a7565b3593611b65613e10565b848652600980855260ff600191818360408b20015460a81c1615611e4957878952808752604089208381015460a01c831615611bb35760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e3157611be48160005260096020526001600160a01b0360406000205416331490565b15611e1157611bf281613b65565b93818a52828952611c08600260408c200161395f565b946001600160801b0394858751168683161015611df957838c52848b5260408c205460f01c1615611de157918493918a611c5485878f9a99808c9986928d511603169a015116906135a4565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d2d60408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611dc8575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611d058b85886147f8565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d71575b505050505050600101929190611b45565b813b15610e0a57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611db4575b80808080611d60565b611dbd906134c5565b61052b578438611dab565b818601600160a01b60ff60a01b19825416179055611cbb565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082611ea792610a6b9452600a602052206138e1565b60405191829160208352602083019061344c565b503461063257602080600319360112610aec5760043590611eda613e10565b8183526009815260ff600160408520015460a81c16156120cb57611efd82613c48565b60058110156120b75760048103611f265760248360405190634a5541ef60e01b82526004820152fd5b60038103611f46576024836040519063fe19f19f60e01b82526004820152fd5b60021461209f57611f6d8260005260096020526001600160a01b0360406000205416331490565b15612080578183526009815260ff604084205460f01c161561206857818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b612010575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612054575b80611fe1565b61205d906134c5565b6104a357823861204e565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610632576020366003190112610632576004356001600160a01b03908181168091036104a357818354163381036121b3575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161219f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610632576020366003190112610632576121f66133a6565b9080546001600160a01b0380821693338503612248576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610632576020366003190112610632576001600160a01b036122916133a6565b1680156122ae578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106325760203660031901126106325760206122fe600435613b21565b6001600160a01b0360405191168152f35b50346106325760403660031901126106325767ffffffffffffffff6004358181116104a35761234290369060040161341b565b9091602490813590811161052b5761235e90369060040161341b565b612369929192613e10565b80840361279c57855b84811061237d578680f35b6123888186886138a7565b35906123958187896138a7565b35885260036020526001600160a01b036040892054166123be6123b98386896138a7565b6138cd565b906123c7613e10565b838a52600960205260ff600160408c20015460a81c161561278657838a52600960205260ff600160408c20015460a01c1661276f578015612758576001600160801b0382161561274157838a5260036020526001600160a01b0360408b205416918282141580612731575b61270d5761243f8561466b565b6001600160801b0381166001600160801b038316116126dd5750908a9291858452600960205260408420926124c56001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff196124a787608094851c614693565b938c8b52600960205260408b2001938454931b16911617815561395f565b6001600160801b036124e981602084015116928260408183511692015116906135a4565b1611156126ac575b86855260096020526001600160a01b0360016040872001541661251e6001600160801b03841685836147f8565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126a2575b612638575b83331415908161262d575b81612622575b506125b0575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612372565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161260a575b8080612579565b612613906134c5565b61261e578738612603565b8780fd5b905083141538612573565b843b1515915061256d565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161268e575b5050612562565b612697906134c5565b61052b578438612687565b50803b151561255d565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124f1565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061273b85614554565b15612432565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a6576108996020916145bd565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120cb578061284883613c48565b926005841015611ac357600260209403612869575b50506040519015158152f35b815260098352604090205460f01c60ff169050388061285d565b503461063257806003193601126106325760206001600160a01b0360085416604051908152f35b503461063257602080600319360112610aec57600435906128c9613e10565b8183526009815260ff600160408520015460a81c16156120cb578183526009815260ff600160408520015460a01c1615612a505761290682614554565b156120805781600052600381526001600160a01b038060406000205416151580612a48575b80612a2e575b612a16577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260038352604060002054169182159283156129db575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129c3575080f35b60249060405190637e27328960e01b82526004820152fd5b6129fc85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612971565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615612931565b50600061292b565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257612a90366133e6565b60405191602083019383851067ffffffffffffffff861117611ad757611109946040528584526139b4565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063257602090816003193601126106325760043590612b2c613e10565b818152600980845260ff600160408420015460a81c1615612da85782825280845260408220600181015460a01c60ff1615612b795760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612d9057612ba48260005260096020526001600160a01b0360406000205416331490565b1561208057612bb282613b65565b93828452818152612bc86002604086200161395f565b926001600160801b039182855116838816101561209f5781865283815260ff604087205460f01c1615612068577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612c31888584818b9c818c9d9c511603169a015116906135a4565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612d76575b01896fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612ce28d84876147f8565b8c612d116040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612d25578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d67575b81818080808480f35b612d70906134c5565b38612d5e565b60018101600160a01b60ff60a01b19825416179055612c75565b6024826040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b5034610632576003199060203683018113610aec576004359167ffffffffffffffff93848411610aec5761014090843603011261063257612dfe613e10565b60405193612e0b856134a8565b612e17846004016133d2565b8552612e25602485016133d2565b6020860152612e366044850161356c565b604086015260648401356001600160a01b03811681036104a3576060860152612e616084850161349b565b6080860152612e7260a4850161349b565b60a0860152612e8360c48501613818565b60c086015260e4840135908111610aec5783019136602384011215610aec576004830135612eb08161382a565b93612ebe604051958661352e565b8185526024602086019260061b820101933685116106325750602401905b838210612efe5760206116cc886116c1898960e0840152610104369101613878565b82604091612f0c3685613842565b815201910190612edc565b503461063257806003193601126106325760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461063257611109612f64366133e6565b916135d3565b50346106325780600319360112610632576020600754604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657612fc190613c48565b9060058210156114a75760208215838115612fe2575b506040519015158152f35b600191501482612fd7565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120cb57602091604082828152600985522060ff815460f01c168061307b575b613052575b50506001600160801b0360405191168152f35b61307492506001600160801b03600261306e9201541691613b65565b906135a4565b388061303f565b5060ff600182015460a01c161561303a565b5034610632576040366003190112610632576130a76133a6565b6024356130b381613b21565b33151580613173575b80613149575b6131195781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff604085205416156130c2565b50336001600160a01b03821614156130bc565b50346106325760203660031901126106325760206122fe600435613580565b50346106325780600319360112610632576040519080600191600154928360011c9260018516948515613260575b60209586861081146113bf5785885287949392918790821561139d57505060011461320657505061132f9250038361352e565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061324857505061132f93508201013880611321565b80548389018501528794508693909201918101613230565b93607f16936131d3565b5034610632578060031936011261063257602060405167016345785d8a00008152f35b905034610aec576020366003190112610aec576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613334575b811561330a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613303565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506132fc565b60005b8381106133715750506000910152565b8181015183820152602001613361565b9060209161339a8151809281855285808601910161335e565b601f01601f1916010190565b600435906001600160a01b038216820361062d57565b602435906001600160a01b038216820361062d57565b35906001600160a01b038216820361062d57565b606090600319011261062d576001600160a01b0390600435828116810361062d5791602435908116810361062d579060443590565b9181601f8401121561062d5782359167ffffffffffffffff831161062d576020808501948460051b01011161062d57565b90815180825260208080930193019160005b82811061346c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161345e565b3590811515820361062d57565b610120810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757604052565b610180810190811067ffffffffffffffff821117611ad757604052565b6060810190811067ffffffffffffffff821117611ad757604052565b6040810190811067ffffffffffffffff821117611ad757604052565b90601f8019910116810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757601f01601f191660200190565b35906001600160801b038216820361062d57565b61358981613b21565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116135bd57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561380057600091848352602091600383526040928284862054161515806137f8575b806137e0575b6137c9578685526003815282848620541694873315159384613719575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876136e1575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136b35750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61370282600052600560205260406000206001600160a01b03198154169055565b87835260048452868320805460001901905561364f565b91929380915090613788575b156137335790878392613626565b848887613750576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156137ad575b806137255750878252600583523384868420541614613725565b5085825260068352848220338352835260ff8583205416613793565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615613609565b506001613603565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361062d57565b67ffffffffffffffff8111611ad75760051b60200190565b919082604091031261062d5760405161385a81613512565b602061387381839561386b8161356c565b855201613818565b910152565b919082604091031261062d5760405161389081613512565b602080829461389e816133d2565b84520135910152565b91908110156138b75760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361062d5790565b9081546138ed8161382a565b926040936138fe604051918261352e565b82815280946020809201926000526020600020906000935b85851061392557505050505050565b6001848192845161393581613512565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613916565b9060405161396c816134f6565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062d5790565b35801515810361062d5790565b91906139c18282856135d3565b803b6139ce575b50505050565b613a2a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613381565b03906020816000938185885af190829082613ac0575b5050613a775782613a4f61463b565b8051919082613a705760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aa85750388080806139c8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613b19575b81613add6020938361352e565b81010312610aec5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106325750903880613a40565b3d9150613ad0565b8060005260036020526001600160a01b03604060002054169081156129c3575090565b8051156138b75760200190565b80518210156138b75760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b8860406000206138e1565b9084846020613b9685613b44565b5101511611613c3e57600052600960205260406000208484825460c81c161115613c2957506001600160801b039081613bce82613b44565b515116946001948594855b613be8575b5050505050505090565b8351871015613c2457828282613bfe8a88613b51565b5101511611613c24578585889981613c17849b89613b51565b5151160116980196613bd9565b613bde565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613c6f575050600490565b805460f81c613cc8575460a01c64ffffffffff164210613cc257613c9281613b65565b9060005260096020526001600160801b038060026040600020015416911610600014613cbd57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613e05575b80613ded575b613dd6579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d9e575b169283613d88575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d64565b613dbf86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d5c565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613cfb565b508181161515613cf5565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e4257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e8e6001600160801b0360408401511660206101008501510151906146ae565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452a57801561450057815180156144d6577f000000000000000000000000000000000000000000000000000000000000000081116144a5575064ffffffffff6020613ef784613b44565b5101511681101561444e5750600090819082815184905b8082106143bd575050505064ffffffffff421664ffffffffff821681101561437d5750506001600160801b0316808203614346575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140aa8951996000198b0190613b51565b51015160c81b169560f01b16911617171717845560005b8181106142a1575050600185016007556001600160a01b036020830151168015613800576140f7866001600160a01b0392613ccf565b16614270576141226001600160a01b036060840151166001600160801b038351169030903390614787565b6001600160801b0360208201511680614240575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661423561421660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141bf8c613512565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061344c565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61426a906001600160a01b036060850151166001600160a01b036101008601515116903390614787565b38614136565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142be8160e0870151613b51565b51825468010000000000000000811015611ad757600181018085558110156138b757600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140c1565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143e1906001600160801b036143d88588613b51565b51511690614693565b9364ffffffffff8060206143f58685613b51565b5101511694168085111561441157506001849301909291613f0e565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061445f84613b44565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614599575b5050821561458757505090565b9091506145943392613580565b161490565b60ff929450906040918152600660205281812033825260205220541691388061457a565b8060005260096020526145d6600260406000200161395f565b816000526009602052604060002060ff600182015460a01c1660001461460957506001600160801b039150602001511690565b5460f81c61461e575061461b90613b65565b90565b61461b91506001600160801b0360408183511692015116906135a4565b3d15614666573d9061464c82613550565b9161465a604051938461352e565b82523d6000602084013e565b606090565b61461b90614678816145bd565b90600052600960205260026040600020015460801c906135a4565b9190916001600160801b03808094169116019182116135bd57565b919091604051906146be82613512565b600091828152826020820152936001600160801b03928383169182156147685767016345785d8a000080821161473157506146fa8591846148e9565b166020870192818452111561471d57509082614718925116906135a4565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061477c82613512565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ad7576147f69260405261484d565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147f69161484d60648361352e565b6001600160a01b031690614878600080836020829551910182875af161487161463b565b9084614998565b9081519182151592836148c1575b5050506148905750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610aec5760200151908115918215036106325750388080614886565b9091906000198382098382029182808310920391808303921461498757670de0b6b3a7640000908183101561495057947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149d757508051156149ad57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614a22575b6149e8575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149e056fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"6080806040523461001757615f2f90816200001d8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c63e9dc63751461002757600080fd5b346143a95760403660031901126143a9576001600160a01b0360043516600435036143a9576100566080614954565b60006080819052606060a081905260c082905260e0819052610120819052610140819052610160819052610180526101a0526004356001600160a01b038116610100526100a290614ae2565b610120526100ba6004356001600160a01b0316614cfa565b61014052610100516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b6576000916148c3575b506001600160a01b0361012b911680608052614e4b565b60a052610100516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b6576fffffffffffffffffffffffffffffffff916000916148a4575b501660c052610100516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156143b657600090614867575b6101f99150614f98565b61016052610100516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b657600091614838575b5060c0516fffffffffffffffffffffffffffffffff168015614822576fffffffffffffffffffffffffffffffff6127108193021604166101206080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102ca81614971565b519020610407602963ffffffff6103176102f08261016861ffff8860101c16061661570d565b91601e604660ff61030d8460146050848d60081c1606011661570d565b981606011661570d565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261035781518092602060248801910161490c565b83017f2c00000000000000000000000000000000000000000000000000000000000000602482015261039382518093602060258501910161490c565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103d1835180946020602786860101910161490c565b01017f252900000000000000000000000000000000000000000000000000000000000060278201520360098101845201826149fd565b61043f6fffffffffffffffffffffffffffffffff6040608001511660ff6104386001600160a01b0360805116615094565b16906151fd565b6104536001600160a01b0360805116614cfa565b90602060800151602460206001600160a01b03608080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b657602491600091614803575b5060206001600160a01b03608080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156143b657610517926000916147d4575b5064ffffffffff8091169116615548565b610140516101a0519092916105a1602161053e6064610537818706615a26565b950461570d565b604051948161055787935180926020808701910161490c565b820161056c825180936020808501910161490c565b017f250000000000000000000000000000000000000000000000000000000000000060208201520360018101855201836149fd565b610120608001519260e0608001519660a06080015196604051996105c48b614954565b8a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c083011117614405576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a082015161069460c0840151845190615b32565b9061097b61015c604051926106a8846149e1565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526106eb6040516106e18161498d565b60008152866159e9565b156147cc576090945b6106fd8661570d565b916040519586938493661e339034b21e9160c91b6020860152610949835195869261072f84602784016020890161490c565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b60358584010152610776855180966020604288870101910161490c565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661087c91889160f99091019060200161490c565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b6101408201528751976109179189916101519091019060200161490c565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d970101010101910161490c565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c810190915201826149fd565b61010083015261012082015260286101208301516040519061099c8261498d565b60008252610c4261015c604051926109b3846149e1565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109e684615e2e565b6109ef82615eac565b808211156147c45750945b610a0587870161570d565b91604051958693661e339034b21e9160c91b60208601528151610a2f81602788016020860161490c565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a7282518093602060428501910161490c565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b6e82518093602060f98501910161490c565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610bfd8251809360206101518501910161490c565b01661e17ba32bc3a1f60c91b610151820152610c248251809360206101588501910161490c565b01631e17b39f60e11b6101588201520361013c8101845201826149fd565b610160840152016101808201526028602083015160405190610c638261498d565b60008252610cad61015c60405192610c7a846149e1565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109e684615e2e565b8352016020820152610fe860808301516030604051610ccb8161498d565b60008152610f7261015c60405194610ce2866149e1565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d1586615e2e565b610d1e82615eac565b808211156147bc5750935b610d356028860161570d565b91604051978893661e339034b21e9160c91b60208601528151610d5f81602788016020860161490c565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610da282518093602060428501910161490c565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610e9e82518093602060f98501910161490c565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f2d8251809360206101518501910161490c565b01661e17ba32bc3a1f60c91b610151820152610f548251809360206101588501910161490c565b01631e17b39f60e11b6101588201520361013c8101865201846149fd565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e0840152610100830151610160840151845191615193565b6060820152604051908161010081011067ffffffffffffffff6101008401111761440557610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e08301528251916101208401519160608101519460405161113e816149a9565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060408201526040519661119b88614954565b61011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b011117614405576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761440557611c79611cda9160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611830615af9565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611cd560d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161196260b88660208501936118a281605e84018761490c565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261190782518093602060938501910161490c565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a78201520360988101885201866149fd565b61196a615af9565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119d081606b8a018461490c565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a15825180936020608e8501910161490c565b019082608e830152611a5960a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b5201896149fd565b611b9f610108611a67615af9565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611af381518092602060738701910161490c565b8201908760738301526076820152875190611b1282609683018861490c565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a6149fd565b611ba7615af9565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a288019061490c565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cbb82518093602060c48501910161490c565b019160c483015260c78201520360b88101875201856149fd565b615193565b92611cec611ce6614f26565b896159e9565b9788156147a1575b50604051611d01816149c5565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c087011117614405576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a08601528960001461457c5760405161212f8161498d565b60008152995b1561441b57604051806101e081011067ffffffffffffffff6101e083011117614405576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761440557613b429c612dfd6036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ece9f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612d998151809260208a8c01910161490c565b8701612dae8251809360208a8501910161490c565b01612dc2825180936020898501910161490c565b01612dd6825180936020888501910161490c565b01612dea825180936020878501910161490c565b01918201520360168101865201846149fd565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e426026998260208c945194859301910161490c565b8901612e578251809360208c8501910161490c565b01612e6b8251809360208b8501910161490c565b01612e7f8251809360208a8501910161490c565b01612e93825180936020898501910161490c565b01612ea7825180936020888501910161490c565b01612ebb825180936020878501910161490c565b019182015203600d8101895201876149fd565b613761604c60e0830151610100840151936134bd6130f06060604084015193015196612efa8186615d72565b946130eb61012b604051612f0d816149e1565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612f7781518092602060378701910161490c565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130bb9184916101209091019060200161490c565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b810190915201876149fd565b615d72565b956132cf61012b604051613103816149e1565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261316d81518092602060378701910161490c565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132aa8251809360206101208501910161490c565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a5201886149fd565b6132d98184615dda565b926134b861012b6040516132ec816149e1565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261335681518092602060378701910161490c565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134938251809360206101208501910161490c565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101875201856149fd565b615dda565b9061369c61012b6040516134d0816149e1565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261353a81518092602060378701910161490c565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136778251809360206101208501910161490c565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b8101855201836149fd565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261370281518092602060458901910161490c565b840161371882518093602060458501910161490c565b0161372d82518093602060458501910161490c565b0161374282518093602060458501910161490c565b01661e17ba32bc3a1f60c91b604582015203602c8101845201826149fd565b613a4161019a6101408401516101a0850151906137a261379c61379661379060e060408b01519a01519461570d565b9461570d565b9761570d565b9161570d565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e8601526101279061393d815180926020858a01910161490c565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139a78251809360208b8501910161490c565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b946139ea825180936020898501910161490c565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a2d825180936020878501910161490c565b01918201520361017a8101855201836149fd565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613acd815180926020607b8901910161490c565b8401613ae3825180936020607b8501910161490c565b01613af8825180936020607b8501910161490c565b01613b0d825180936020607b8501910161490c565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b8201520360618101845201826149fd565b6101805260a051610100516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156143b6576000916143c2575b506089613bae613cd092614cfa565b9260e0608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613bf581518092602060408801910161490c565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613c5a82518093602060638501910161490c565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613c9b82518093602060868501910161490c565b017f227d5d000000000000000000000000000000000000000000000000000000000060868201520360698101845201826149fd565b6101205160a051610140516080519193929091613cf5906001600160a01b0316614cfa565b91613d0160243561570d565b92602460206001600160a01b03608080015116604051928380927fb2564569000000000000000000000000000000000000000000000000000000008252823560048301525afa9081156143b65760009161436c575b50936142e09661406860e361426f966094966142799a9661417e9a6000146142e457604051613d84816149c5565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461400460208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613eb48160558c018461490c565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613f3e8260b183018a61490c565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613f7982518093602060c38501910161490c565b01613fb27f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c784019061490c565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c7820152613ff082518093602060d18501910161490c565b019260d184015251809360d584019061490c565b019060d582015261401f82518093602060df8501910161490c565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df820152614059825180936020878501910161490c565b010360c38101855201836149fd565b61012051906141d961407b60243561570d565b916140fa602d604051809560208201976a029b0b13634b2b9102b19160ad1b89526140b0815180926020602b8701910161490c565b82017f2023000000000000000000000000000000000000000000000000000000000000602b8201526140eb825180936020878501910161490c565b0103600d8101865201846149fd565b610180516141079061585e565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a0152614148815180926020602e8d01910161490c565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e84019061490c565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d84019061490c565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d82015261423a82518093602060928501910161490c565b017f227d00000000000000000000000000000000000000000000000000000000000060928201520360748101845201826149fd565b60e081905261585e565b6142cc603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526142bc815180926020868601910161490c565b810103601d8101845201826149fd565b60405191829160208352602083019061492f565b0390f35b6040516142f081614971565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613e48565b90506020959195813d6020116143ae575b8161438a602093836149fd565b810103126143a957519384151585036143a957909490936142e0613d56565b600080fd5b3d915061437d565b6040513d6000823e3d90fd5b90506020813d6020116143fd575b816143dd602093836149fd565b810103126143a957516001600160a01b03811681036143a9576089613b9f565b3d91506143d0565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761440557610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e000000000000000061010082015299612382565b604051806101c081011067ffffffffffffffff6101c083011117614405576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612135565b6147b59198506147af614f5f565b906159e9565b9638611cf4565b905093610d29565b9050946109fa565b60d0946106f4565b6147f6915060203d6020116147fc575b6147ee81836149fd565b810190614a47565b38610506565b503d6147e4565b61481c915060203d6020116147fc576147ee81836149fd565b386104b0565b634e487b7160e01b600052601260045260246000fd5b61485a915060203d602011614860575b61485281836149fd565b810190614a1f565b38610253565b503d614848565b506020813d60201161489c575b81614881602093836149fd565b810103126143a9575160058110156143a9576101f9906101ef565b3d9150614874565b6148bd915060203d6020116148605761485281836149fd565b38610195565b90506020813d602011614904575b816148de602093836149fd565b810103126143a957516001600160a01b03811681036143a9576001600160a01b03610114565b3d91506148d1565b60005b83811061491f5750506000910152565b818101518382015260200161490f565b906020916149488151809281855285808601910161490c565b601f01601f1916010190565b610140810190811067ffffffffffffffff82111761440557604052565b6080810190811067ffffffffffffffff82111761440557604052565b6020810190811067ffffffffffffffff82111761440557604052565b6060810190811067ffffffffffffffff82111761440557604052565b60c0810190811067ffffffffffffffff82111761440557604052565b6040810190811067ffffffffffffffff82111761440557604052565b90601f8019910116810190811067ffffffffffffffff82111761440557604052565b908160209103126143a957516fffffffffffffffffffffffffffffffff811681036143a95790565b908160209103126143a9575164ffffffffff811681036143a95790565b67ffffffffffffffff811161440557601f01601f191660200190565b6020818303126143a95780519067ffffffffffffffff82116143a9570181601f820112156143a9578051614ab381614a64565b92614ac160405194856149fd565b818452602082840101116143a957614adf916020808501910161490c565b90565b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa928315614cef57600093614ccc575b50815192614b1f846149e1565b60118452614b546020947f5341422d56322d4c4f434b55502d4c494e00000000000000000000000000000086820152826159e9565b15614b925750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614b88836149e1565b600d835282015290565b614bcf8351614ba0816149e1565b601181527f5341422d56322d4c4f434b55502d44594e00000000000000000000000000000086820152826159e9565b15614c0d5750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c03836149e1565b600e835282015290565b614c4a8351614c1b816149e1565b601181527f5341422d56322d4c4f434b55502d54524100000000000000000000000000000086820152826159e9565b15614c885750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614c7e836149e1565b600f835282015290565b614cc89083519384937f814a8a2e00000000000000000000000000000000000000000000000000000000855260048501526024840152604483019061492f565b0390fd5b614ce891933d8091833e614ce081836149fd565b810190614a80565b9138614b12565b82513d6000823e3d90fd5b6001600160a01b03168060405191614d11836149a9565b602a8352602083016040368237835115614e055760309053825160019060011015614e0557607860218501536029905b808211614d8a575050614d52575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614df0577f3031323334353637383961626364656600000000000000000000000000000000901a614dc68487615a15565b5360041c918015614ddb576000190190614d41565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b3d15614e46573d90614e2c82614a64565b91614e3a60405193846149fd565b82523d6000602084013e565b606090565b6000809160405160208101906395d89b4160e01b825260048152614e6e816149e1565b51915afa614e7a614e1b565b90158015614f1a575b614ee05780602080614e9a93518301019101614a80565b601e815111600014614adf5750604051614eb3816149e1565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614eed816149e1565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614e83565b60405190614f33826149e1565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f6c826149e1565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b600581101561507e5760048103614fb25750614adf614f5f565b60038103614ff45750604051614fc7816149e1565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b600181036150365750604051615009816149e1565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361504557614adf614f26565b604051615051816149e1565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150cc816149e1565b6000928392839251915afa6150df614e1b565b9080615116575b156151125760208180518101031261510e57602001519060ff8216820361510b575090565b80fd5b5080fd5b5090565b5060208151146150e6565b6040519061512e826149e1565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615167826149e1565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151fb9294936040519586926020946151b58151809288808901910161490c565b84016151c98251809388808501910161490c565b016151dc8251809387808501910161490c565b016151ef8251809386808501910161490c565b010380855201836149fd565b565b801561550d57600091806154e8575090505b60019080828110156152795750505061522661515a565b614adf60226040518361524382955180926020808601910161490c565b81017f203100000000000000000000000000000000000000000000000000000000000060208201520360028101845201826149fd565b66038d7ea4c68000111561548b5760409081519060a0820182811067ffffffffffffffff821117614405578084526152b08161498d565b6000815282528251906152c2826149e1565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152fc816149e1565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615333816149e1565b8581527f4200000000000000000000000000000000000000000000000000000000000000838201526060840152835161536b816149e1565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b61545f575b508451946153b2866149e1565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b82811061544c575050505061542d615433917f2000000000000000000000000000000000000000000000000000000000000000602787015260088652615428866149e1565b61570d565b91615a26565b916005851015614e0557614adf9460051b015192615193565b81810184015188820185015283016153e3565b9591926103e89081851061548257508680916064600a87040695049301966153a0565b939296506153a5565b5050615495615121565b614adf6028604051836154b282955180926020808601910161490c565b81017f203939392e39395400000000000000000000000000000000000000000000000060208201520360088101845201826149fd565b600a0a9182156154f957500461520f565b80634e487b7160e01b602492526012600452fd5b505060405161551b816149e1565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155b0575061555d61515a565b614adf60266040518361557a82955180926020808601910161490c565b81017f203120446179000000000000000000000000000000000000000000000000000060208201520360068101845201826149fd565b61270f811161567f576001810361563c57614adf60206156046040516155d5816149e1565b600481527f2044617900000000000000000000000000000000000000000000000000000000838201529361570d565b604051938161561c869351809286808701910161490c565b82016156308251809386808501910161490c565b010380845201826149fd565b614adf6020615604604051615650816149e1565b600581527f2044617973000000000000000000000000000000000000000000000000000000838201529361570d565b50615688615121565b614adf602a604051836156a582955180926020808601910161490c565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a8101845201826149fd565b906156e582614a64565b6156f260405191826149fd565b8281528092615703601f1991614a64565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615850575b506d04ee2d6d415b85acef810000000080831015615841575b50662386f26fc1000080831015615832575b506305f5e10080831015615823575b5061271080831015615814575b506064821015615804575b600a809210156157fa575b6001908160216157a5600187016156db565b95860101905b6157b7575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157f5579190826157ab565b6157b0565b9160010191615793565b9190606460029104910191615788565b6004919392049101913861577d565b60089193920491019138615770565b60109193920491019138615761565b6020919392049101913861574f565b604093508104915038615736565b908151156159d45760405191615873836149a9565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805192600291600285018095116159be5760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159be576159119060029694961b6156db565b926020840192829183518401976020890192835194600085525b8a81106159715750505050600393949596505251068060011461595e57600214615953575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c16870101518785015316840101518582015301969961592b565b634e487b7160e01b600052601160045260246000fd5b90506040516159e28161498d565b6000815290565b90815181519081811493846159ff575050505090565b60209293945082012092012014388080806157b0565b908151811015614e05570160200190565b80615a3857506040516159e28161498d565b600a811015615a9d57615a4a9061570d565b614adf602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a8d815180926020868601910161490c565b81010360028101845201826149fd565b615aa69061570d565b614adf602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615ae9815180926020868601910161490c565b81010360018101845201826149fd565b60405190615b06826149e1565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d6457615b40615af9565b906127109081039081116159be57614adf91615b5e6101369261570d565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615bea81518092602060578801910161490c565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c7282518093602060a78501910161490c565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cd382518093602060d58501910161490c565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b610132820152036101168101845201826149fd565b50506040516159e28161498d565b60306151fb919392936040519481615d9487935180926020808701910161490c565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615dcb825180936020878501910161490c565b010360108101855201836149fd565b60256151fb919392936040519481615dfc87935180926020808701910161490c565b820164010714051160dd1b6020820152615e1f825180936020878501910161490c565b010360058101855201836149fd565b60009080518015615ea457906000916000915b818310615e5357505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e868785615a15565b511614615e9c575b600d01936001019190615e41565b849350615e8e565b505050600090565b60009080518015615ea457906000916000915b818310615ed15750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f048785615a15565b511614615f1a575b601001936001019190615ebf565b849350615f0c56fea164736f6c6343000817000a"; + hex"6080806040523461001757615f5890816200001d8239f35b600080fdfe600436101561000d57600080fd5b60003560e01c63e9dc63751461002257600080fd5b3461442a57604036600319011261442a576001600160a01b03600435166004350361442a5761022060405260006080819052606060a081905260c082905260e08290526101008190526101208190526101608190526101808190526101a08190526101c0526101e0819052610200526004356001600160a01b038116610140526100ab90614b3b565b610160526100c36004356001600160a01b0316614d53565b61018052610140516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561443757600091614909575b506001600160a01b03610134911680608052614e74565b60a052610140516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576fffffffffffffffffffffffffffffffff916000916148ea575b501660c052610140516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576000906148ad575b6102029150614fc1565b6101a052610140516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156144375760009161487e575b5060c0516fffffffffffffffffffffffffffffffff168015614868576fffffffffffffffffffffffffffffffff6127108193021604166101606080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102d38161499a565b51902061041360296102f563ffffffff61016861ffff8660101c160616615736565b61032363ffffffff601e604660ff6103198460146050848d60081c16060116615736565b9816060116615736565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610363815180926020602488019101614952565b83017f2c00000000000000000000000000000000000000000000000000000000000000602482015261039f825180936020602585019101614952565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103dd8351809460206027868601019101614952565b01017f25290000000000000000000000000000000000000000000000000000000000006027820152036009810184520182614a26565b61044b6fffffffffffffffffffffffffffffffff6040608001511660ff6104446001600160a01b03608051166150bd565b1690615226565b61045f6001600160a01b0360805116614d53565b90602060800151602460206001600160a01b0360c06080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa801561443757602491600091614849575b5060206001600160a01b0360c06080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa8015614437576105259260009161481a575b5064ffffffffff8091169116615571565b610180516101e0519092916105af602161054c6064610545818706615a4f565b9504615736565b6040519481610565879351809260208087019101614952565b820161057a8251809360208085019101614952565b017f25000000000000000000000000000000000000000000000000000000000000006020820152036001810185520183614a26565b6101606080015192610120608001519660e06080015196604051998a61014081011067ffffffffffffffff6101408d01111761444b576101408b016040528a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106bd60c0840151845190615b5b565b906109a461015c604051926106d184614a0a565b600884527f50726f6772657373000000000000000000000000000000000000000000000000602085015261071460405161070a816149b6565b6000815286615a12565b15614812576090945b61072686615736565b916040519586938493661e339034b21e9160c91b60208601526109728351958692610758846027840160208901614952565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b6035858401015261079f8551809660206042888701019101614952565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108a591889160f990910190602001614952565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094091899161015190910190602001614952565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614952565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c81019091520182614a26565b6101008301526101208201526028610120830151604051906109c5826149b6565b60008252610c6b61015c604051926109dc84614a0a565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b610a1882615ed5565b8082111561480a5750945b610a2e878701615736565b91604051958693661e339034b21e9160c91b60208601528151610a58816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a9b825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b9782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c2682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610c4d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810184520182614a26565b610160840152016101808201526028602083015160405190610c8c826149b6565b60008252610cd661015c60405192610ca384614a0a565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b835201602082015261101160808301516030604051610cf4816149b6565b60008152610f9b61015c60405194610d0b86614a0a565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d3e86615e57565b610d4782615ed5565b808211156148025750935b610d5e60288601615736565b91604051978893661e339034b21e9160c91b60208601528151610d88816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dcb825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ec782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f5682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610f7d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810186520184614a26565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e08401526101008301516101608401518451916151bc565b6060820152604051908161010081011067ffffffffffffffff6101008401111761444b57610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161012084015191606081015194604051611167816149d2565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051968761014081011067ffffffffffffffff6101408a01111761444b57610140880160405261011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b01111761444b576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761444b57611cbc611d1d9160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611873615b22565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d1860d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d2200009384604085015280516119a560b88660208501936118e581605e840187614952565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261194a825180936020609385019101614952565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a7820152036098810188520186614a26565b6119ad615b22565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a1381606b8a0184614952565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a58825180936020608e85019101614952565b019082608e830152611a9c60a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b520189614a26565b611be2610108611aaa615b22565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b36815180926020607387019101614952565b8201908760738301526076820152875190611b55826096830188614952565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a614a26565b611bea615b22565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614952565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cfe82518093602060c485019101614952565b019160c483015260c78201520360b8810187520185614a26565b6151bc565b92611d2f611d29614f4f565b89615a12565b9788156147e7575b50604051611d44816149ee565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c08701111761444b576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145c257604051612172816149b6565b60008152995b1561446157604051806101e081011067ffffffffffffffff6101e08301111761444b576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761444b57613b859c612e406036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f119f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612ddc8151809260208a8c019101614952565b8701612df18251809360208a85019101614952565b01612e058251809360208985019101614952565b01612e198251809360208885019101614952565b01612e2d8251809360208785019101614952565b0191820152036016810186520184614a26565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e856026998260208c9451948593019101614952565b8901612e9a8251809360208c85019101614952565b01612eae8251809360208b85019101614952565b01612ec28251809360208a85019101614952565b01612ed68251809360208985019101614952565b01612eea8251809360208885019101614952565b01612efe8251809360208785019101614952565b019182015203600d810189520187614a26565b6137a4604c60e0830151610100840151936135006131336060604084015193015196612f3d8186615d9b565b9461312e61012b604051612f5081614a0a565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fba815180926020603787019101614952565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130fe91849161012090910190602001614952565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b81019091520187614a26565b615d9b565b9561331261012b60405161314681614a0a565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131b0815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132ed82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a520188614a26565b61331c8184615e03565b926134fb61012b60405161332f81614a0a565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613399815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134d682518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810187520185614a26565b615e03565b906136df61012b60405161351381614a0a565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261357d815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136ba82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810185520183614a26565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e0000000000000000000000000000000000000000000000000000006040860152613745815180926020604589019101614952565b840161375b825180936020604585019101614952565b01613770825180936020604585019101614952565b01613785825180936020604585019101614952565b01661e17ba32bc3a1f60c91b604582015203602c810184520182614a26565b613a8461019a6101408401516101a0850151906137e56137df6137d96137d360e060408b01519a015194615736565b94615736565b97615736565b91615736565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e86015261012790613980815180926020858a019101614952565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139ea8251809360208b85019101614952565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a2d8251809360208985019101614952565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a708251809360208785019101614952565b01918201520361017a810185520183614a26565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b10815180926020607b89019101614952565b8401613b26825180936020607b85019101614952565b01613b3b825180936020607b85019101614952565b01613b50825180936020607b85019101614952565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b820152036061810184520182614a26565b610140608001526000806001600160a01b0360c0608001511660405160208101907fb2564569000000000000000000000000000000000000000000000000000000008252602435602482015260248152613bde816149d2565b51915afa613bea614aa9565b61012081905290158015610200526144435760208180518101031261442a5760200151801515810361442a575b151560e05260a051610140516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614437576000916143ec575b506141fd6142ee609461436094613db66089613c936142f997614d53565b92610120608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613cdb815180926020604088019101614952565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613d40825180936020606385019101614952565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d81825180936020608685019101614952565b017f227d5d00000000000000000000000000000000000000000000000000000000006086820152036069810184520182614a26565b6101605160a0516101805160805190926140e79160e39190613de0906001600160a01b0316614d53565b94613dec602435615736565b60e0519096901561436457604051613e03816149ee565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461408360208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613f338160558c0184614952565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613fbd8260b183018a614952565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ff882518093602060c385019101614952565b016140317f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614952565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c782015261406f82518093602060d185019101614952565b019260d184015251809360d5840190614952565b019060d582015261409e82518093602060df85019101614952565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140d88251809360208785019101614952565b010360c3810185520183614a26565b61016051906142586140fa602435615736565b91614179602d604051809560208201976a029b0b13634b2b9102b19160ad1b895261412f815180926020602b87019101614952565b82017f2023000000000000000000000000000000000000000000000000000000000000602b82015261416a8251809360208785019101614952565b0103600d810186520184614a26565b6101c05161418690615887565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a01526141c7815180926020602e8d019101614952565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614952565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614952565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d8201526142b9825180936020609285019101614952565b017f227d0000000000000000000000000000000000000000000000000000000000006092820152036074810184520182614a26565b610100819052615887565b61434c603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000602083015261433c8151809260208686019101614952565b810103601d810184520182614a26565b604051918291602083526020830190614975565b0390f35b6040516143708161499a565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613ec7565b90506020813d60201161442f575b8161440760209383614a26565b8101031261442a5751906001600160a01b038216820361442a57906141fd613c75565b600080fd5b3d91506143fa565b6040513d6000823e3d90fd5b506001613c17565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761444b57610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123c5565b604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612178565b6147fb9198506147f5614f88565b90615a12565b9638611d37565b905093610d52565b905094610a23565b60d09461071d565b61483c915060203d602011614842575b6148348183614a26565b810190614a70565b38610514565b503d61482a565b614862915060203d602011614842576148348183614a26565b386104bd565b634e487b7160e01b600052601260045260246000fd5b6148a0915060203d6020116148a6575b6148988183614a26565b810190614a48565b3861025c565b503d61488e565b506020813d6020116148e2575b816148c760209383614a26565b8101031261442a5751600581101561442a57610202906101f8565b3d91506148ba565b614903915060203d6020116148a6576148988183614a26565b3861019e565b90506020813d60201161494a575b8161492460209383614a26565b8101031261442a57516001600160a01b038116810361442a576001600160a01b0361011d565b3d9150614917565b60005b8381106149655750506000910152565b8181015183820152602001614955565b9060209161498e81518092818552858086019101614952565b601f01601f1916010190565b6080810190811067ffffffffffffffff82111761444b57604052565b6020810190811067ffffffffffffffff82111761444b57604052565b6060810190811067ffffffffffffffff82111761444b57604052565b60c0810190811067ffffffffffffffff82111761444b57604052565b6040810190811067ffffffffffffffff82111761444b57604052565b90601f8019910116810190811067ffffffffffffffff82111761444b57604052565b9081602091031261442a57516fffffffffffffffffffffffffffffffff8116810361442a5790565b9081602091031261442a575164ffffffffff8116810361442a5790565b67ffffffffffffffff811161444b57601f01601f191660200190565b3d15614ad4573d90614aba82614a8d565b91614ac86040519384614a26565b82523d6000602084013e565b606090565b60208183031261442a5780519067ffffffffffffffff821161442a570181601f8201121561442a578051614b0c81614a8d565b92614b1a6040519485614a26565b8184526020828401011161442a57614b389160208085019101614952565b90565b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa928315614d4857600093614d25575b50815192614b7884614a0a565b60118452614bad6020947f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000008682015282615a12565b15614beb5750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614be183614a0a565b600d835282015290565b614c288351614bf981614a0a565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000008682015282615a12565b15614c665750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c5c83614a0a565b600e835282015290565b614ca38351614c7481614a0a565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000008682015282615a12565b15614ce15750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614cd783614a0a565b600f835282015290565b614d219083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614975565b0390fd5b614d4191933d8091833e614d398183614a26565b810190614ad9565b9138614b6b565b82513d6000823e3d90fd5b6001600160a01b03168060405191614d6a836149d2565b602a8352602083016040368237835115614e5e5760309053825160019060011015614e5e57607860218501536029905b808211614de3575050614dab575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614e49577f3031323334353637383961626364656600000000000000000000000000000000901a614e1f8487615a3e565b5360041c918015614e34576000190190614d9a565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b6000809160405160208101906395d89b4160e01b825260048152614e9781614a0a565b51915afa614ea3614aa9565b90158015614f43575b614f095780602080614ec393518301019101614ad9565b601e815111600014614b385750604051614edc81614a0a565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614f1681614a0a565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614eac565b60405190614f5c82614a0a565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f9582614a0a565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b60058110156150a75760048103614fdb5750614b38614f88565b6003810361501d5750604051614ff081614a0a565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b6001810361505f575060405161503281614a0a565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361506e57614b38614f4f565b60405161507a81614a0a565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150f581614a0a565b6000928392839251915afa615108614aa9565b908061513f575b1561513b5760208180518101031261513757602001519060ff82168203615134575090565b80fd5b5080fd5b5090565b50602081511461510f565b6040519061515782614a0a565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061519082614a0a565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906152249294936040519586926020946151de81518092888089019101614952565b84016151f282518093888085019101614952565b0161520582518093878085019101614952565b0161521882518093868085019101614952565b01038085520183614a26565b565b80156155365760009180615511575090505b60019080828110156152a25750505061524f615183565b614b3860226040518361526c829551809260208086019101614952565b81017f20310000000000000000000000000000000000000000000000000000000000006020820152036002810184520182614a26565b66038d7ea4c6800011156154b45760409081519060a0820182811067ffffffffffffffff82111761444b578084526152d9816149b6565b6000815282528251906152eb82614a0a565b8482526020917f4b000000000000000000000000000000000000000000000000000000000000008382015282840152835161532581614a0a565b8581527f4d000000000000000000000000000000000000000000000000000000000000008382015284840152835161535c81614a0a565b8581527f4200000000000000000000000000000000000000000000000000000000000000838201526060840152835161539481614a0a565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615488575b508451946153db86614a0a565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615475575050505061545661545c917f200000000000000000000000000000000000000000000000000000000000000060278701526008865261545186614a0a565b615736565b91615a4f565b916005851015614e5e57614b389460051b0151926151bc565b818101840151888201850152830161540c565b9591926103e8908185106154ab57508680916064600a87040695049301966153c9565b939296506153ce565b50506154be61514a565b614b386028604051836154db829551809260208086019101614952565b81017f203939392e3939540000000000000000000000000000000000000000000000006020820152036008810184520182614a26565b600a0a918215615522575004615238565b80634e487b7160e01b602492526012600452fd5b505060405161554481614a0a565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155d95750615586615183565b614b386026604051836155a3829551809260208086019101614952565b81017f20312044617900000000000000000000000000000000000000000000000000006020820152036006810184520182614a26565b61270f81116156a8576001810361566557614b38602061562d6040516155fe81614a0a565b600481527f20446179000000000000000000000000000000000000000000000000000000008382015293615736565b60405193816156458693518092868087019101614952565b820161565982518093868085019101614952565b01038084520182614a26565b614b38602061562d60405161567981614a0a565b600581527f20446179730000000000000000000000000000000000000000000000000000008382015293615736565b506156b161514a565b614b38602a604051836156ce829551809260208086019101614952565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a810184520182614a26565b9061570e82614a8d565b61571b6040519182614a26565b828152809261572c601f1991614a8d565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615879575b506d04ee2d6d415b85acef81000000008083101561586a575b50662386f26fc100008083101561585b575b506305f5e1008083101561584c575b506127108083101561583d575b50606482101561582d575b600a80921015615823575b6001908160216157ce60018701615704565b95860101905b6157e0575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a83530491821561581e579190826157d4565b6157d9565b91600101916157bc565b91906064600291049101916157b1565b600491939204910191386157a6565b60089193920491019138615799565b6010919392049101913861578a565b60209193920491019138615778565b60409350810491503861575f565b908151156159fd576040519161589c836149d2565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805192600291600285018095116159e75760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159e75761593a9060029694961b615704565b926020840192829183518401976020890192835194600085525b8a811061599a575050505060039394959650525106806001146159875760021461597c575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699615954565b634e487b7160e01b600052601160045260246000fd5b9050604051615a0b816149b6565b6000815290565b9081518151908181149384615a28575050505090565b60209293945082012092012014388080806157d9565b908151811015614e5e570160200190565b80615a615750604051615a0b816149b6565b600a811015615ac657615a7390615736565b614b38602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615ab68151809260208686019101614952565b8101036002810184520182614a26565b615acf90615736565b614b38602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615b128151809260208686019101614952565b8101036001810184520182614a26565b60405190615b2f82614a0a565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d8d57615b69615b22565b906127109081039081116159e757614b3891615b8761013692615736565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615c13815180926020605788019101614952565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c9b82518093602060a785019101614952565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cfc82518093602060d585019101614952565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b61013282015203610116810184520182614a26565b5050604051615a0b816149b6565b6030615224919392936040519481615dbd879351809260208087019101614952565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615df48251809360208785019101614952565b01036010810185520183614a26565b6025615224919392936040519481615e25879351809260208087019101614952565b820164010714051160dd1b6020820152615e488251809360208785019101614952565b01036005810185520183614a26565b60009080518015615ecd57906000916000915b818310615e7c57505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eaf8785615a3e565b511614615ec5575b600d01936001019190615e6a565b849350615eb7565b505050600090565b60009080518015615ecd57906000916000915b818310615efa5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f2d8785615a3e565b511614615f43575b601001936001019190615ee8565b849350615f3556fea164736f6c6343000817000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index abe47289e..61acdb0d9 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -31,13 +31,16 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { address asset; string assetSymbol; uint128 depositedAmount; + bool isTransferable; string json; + bytes returnData; ISablierV2Lockup sablier; string sablierModel; string sablierStringified; string status; string svg; uint256 streamedPercentage; + bool success; } /// @inheritdoc ISablierV2NFTDescriptor @@ -78,6 +81,13 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { }) ); + // Performs a low-level call to handle older deployments that miss the `isTransferable` function. + (vars.success, vars.returnData) = + address(vars.sablier).staticcall(abi.encodeCall(ISablierV2Lockup.isTransferable, (streamId))); + + // When the call has failed, the stream NFT is assumed to be transferable. + vars.isTransferable = vars.success ? abi.decode(vars.returnData, (bool)) : true; + // Generate the JSON metadata. vars.json = string.concat( '{"attributes":', @@ -93,7 +103,7 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { sablierStringified: vars.sablierStringified, assetAddress: vars.asset.toHexString(), streamId: streamId.toString(), - isTransferable: vars.sablier.isTransferable(streamId) + isTransferable: vars.isTransferable }), '","external_url":"https://sablier.com","name":"', generateName({ sablierModel: vars.sablierModel, streamId: streamId.toString() }), diff --git a/test/fork/Fork.t.sol b/test/fork/Fork.t.sol index e28b446aa..770219d1d 100644 --- a/test/fork/Fork.t.sol +++ b/test/fork/Fork.t.sol @@ -31,7 +31,7 @@ abstract contract Fork_Test is Base_Test { function setUp() public virtual override { // Fork Ethereum Mainnet at a specific block number. - vm.createSelectFork({ blockNumber: 16_126_000, urlOrAlias: "mainnet" }); + vm.createSelectFork({ blockNumber: 19_000_000, urlOrAlias: "mainnet" }); // The base is set up after the fork is selected so that the base test contracts are deployed on the fork. Base_Test.setUp(); diff --git a/test/fork/NFTDescriptor.t.sol b/test/fork/NFTDescriptor.t.sol new file mode 100644 index 000000000..31c096f4c --- /dev/null +++ b/test/fork/NFTDescriptor.t.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; + +import { Fork_Test } from "./Fork.t.sol"; + +abstract contract NFTDescriptor_Fork_Test is Fork_Test { + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor(IERC20 asset, address holder) Fork_Test(asset, holder) { } + + /*////////////////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Loads the Lockup V2.0 contracts pre-deployed on Mainnet. + modifier loadDeployments_V2_0() { + lockupDynamic = ISablierV2LockupDynamic(0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44); + lockupLinear = ISablierV2LockupLinear(0xB10daee1FCF62243aE27776D7a92D39dC8740f95); + _; + } + + /// @dev Loads the Lockup V2.1 contracts pre-deployed on Mainnet. + modifier loadDeployments_V2_1() { + lockupDynamic = ISablierV2LockupDynamic(0x7CC7e125d83A581ff438608490Cc0f7bDff79127); + lockupLinear = ISablierV2LockupLinear(0xAFb979d9afAd1aD27C5eFf4E27226E3AB9e5dCC9); + _; + } + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupDynamic_V2_0(uint256 streamId) external loadDeployments_V2_0 { + streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); + + string memory tokenURIBefore = lockupDynamic.tokenURI(streamId); + + // Set the new NFT descriptor for the previous version of Lockup Dynamic. + resetPrank({ msgSender: lockupDynamic.admin() }); + lockupDynamic.setNFTDescriptor(nftDescriptor); + + string memory tokenURIAfter = lockupDynamic.tokenURI(streamId); + + // Assert that the token URI has not changed. + assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + } + + /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupDynamic_V2_1(uint256 streamId) external loadDeployments_V2_1 { + streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); + + string memory tokenURIBefore = lockupDynamic.tokenURI(streamId); + + // Set the new NFT descriptor for the previous version of Lockup Dynamic. + resetPrank({ msgSender: lockupDynamic.admin() }); + lockupDynamic.setNFTDescriptor(nftDescriptor); + + string memory tokenURIAfter = lockupDynamic.tokenURI(streamId); + + // Assert that the token URI has not changed. + assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + } + + /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupLinear_V2_0(uint256 streamId) external loadDeployments_V2_0 { + streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); + + string memory tokenURIBefore = lockupLinear.tokenURI(streamId); + + // Set the new NFT descriptor for the previous version of Lockup Linear. + resetPrank({ msgSender: lockupLinear.admin() }); + lockupLinear.setNFTDescriptor(nftDescriptor); + + string memory tokenURIAfter = lockupLinear.tokenURI(streamId); + + // Assert that the token URI has not changed. + assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + } + + /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupLinear_V2_1(uint256 streamId) external loadDeployments_V2_1 { + streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); + + string memory tokenURIBefore = lockupLinear.tokenURI(streamId); + + // Set the new NFT descriptor for the previous version of Lockup Linear. + resetPrank({ msgSender: lockupLinear.admin() }); + lockupLinear.setNFTDescriptor(nftDescriptor); + + string memory tokenURIAfter = lockupLinear.tokenURI(streamId); + + // Assert that the token URI has not changed. + assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + } +} diff --git a/test/fork/assets/DAI.t.sol b/test/fork/assets/DAI.t.sol index 6bf507732..6dfa4e3a3 100644 --- a/test/fork/assets/DAI.t.sol +++ b/test/fork/assets/DAI.t.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev A typical 18-decimal ERC-20 asset with a normal total supply. IERC20 constant ASSET = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -16,3 +17,5 @@ contract DAI_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { contract DAI_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract DAI_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } + +contract DAI_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/EURS.t.sol b/test/fork/assets/EURS.t.sol index d75a7ca01..4b3a621e1 100644 --- a/test/fork/assets/EURS.t.sol +++ b/test/fork/assets/EURS.t.sol @@ -6,13 +6,16 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with 2 decimals. IERC20 constant ASSET = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8); -address constant HOLDER = 0x9712c160925403A9458BfC6bBD7D8a1E694C984a; +address constant HOLDER = 0x1bee4F735062CD00841d6997964F187f5f5F5Ac9; contract EURS_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { } contract EURS_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract EURS_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } + +contract EURS_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/SHIB.t.sol b/test/fork/assets/SHIB.t.sol index 6d2f9dcbd..a70933cbf 100644 --- a/test/fork/assets/SHIB.t.sol +++ b/test/fork/assets/SHIB.t.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with a large total supply. IERC20 constant ASSET = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); @@ -16,3 +17,5 @@ contract SHIB_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract SHIB_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract SHIB_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } + +contract SHIB_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDC.t.sol b/test/fork/assets/USDC.t.sol index f253f779a..5e1c8cbbb 100644 --- a/test/fork/assets/USDC.t.sol +++ b/test/fork/assets/USDC.t.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant ASSET = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); @@ -16,3 +17,5 @@ contract USDC_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract USDC_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract USDC_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } + +contract USDC_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDT.t.sol b/test/fork/assets/USDT.t.sol index d2d803eec..631827d3c 100644 --- a/test/fork/assets/USDT.t.sol +++ b/test/fork/assets/USDT.t.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant ASSET = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); @@ -16,3 +17,5 @@ contract USDT_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract USDT_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract USDT_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } + +contract USDT_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } From 84aa3cde50cfd63c78c36f320cedd6ca7a03fb91 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 11 Apr 2024 21:50:37 +0100 Subject: [PATCH 087/132] build: bump sphinx --- bun.lockb | Bin 306637 -> 306637 bytes package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lockb b/bun.lockb index 2949551727093e8e84bd64b7523c7b85388e625a..f93dd2750c48e4fea2a4a03170ad68f283de93e5 100755 GIT binary patch delta 5819 zcmY+|d$ijG0mt#%-AiQxs9LNf6P#%u54d@UdFa||L;wG*G zCIz`H710U`<+;ebmtG!PL8U6NhyoRvlz|$?D+32r+z4EL-{Vp9M?UBG?K#O`?Mb?3 z?G9_!?r^;|?vNedxoO>F=F|JXcFi57@`7-HQRF7V0vHLK=qo$BjL^(EUTA6a|J9&>Ce zRg1@`P9DXXAnMSA{9cL;NT9H{VgTuVw2IJ#OjfZ3Eim>~bfFFAM8z_MkljzwgAQ1e z6f4jLdw<0$M3DQGq7N}R2PoE|2YE}e0SOciR16?JS*r+5$Q-0tf)*GDE4t7I^AN={ zgpi%0=s^dpPb*fS3%0FTg$QzoD*6zEGgYw;J;+Z}Y(N5q!xRHZe@3eaO~`y!u>>tJ z4p(%c4Q5WU3?XEXQ1qY!*5?!}&;|QQ#VSOQJ4(@q7@X;fb?8C<^NI~fpfE!*fV87k zgeGLZpjd(y7&8^!QBM7zFUsP+{~iOE9Qf|J_6rZzo;&9BX;W@Dr_WrpWW^D)XFPG= zqNk#D1JB+w^VZ41vKv>&@4vkEw2|<{;j#12dSL%Omfm*R5_jq1oj#bFs+mXYE@cQI zdyJw79k9NrSb;9s$0}AKg4`@cA7XIwigoBg{y4=3Bv3eBF@W?5T199=X0~DpT42mk zbfFFAiHcVgnK= zloSIY zbZMIT~tmMPYu2lxJNZ&R#71i9N4eTcznDAu6|`8yOF zkU-&1#Q@TGX%(RfnY$HB&;sKgMHkv&-m6%K5VETjJ?MZHC{~~g_D>Y65JB!fMIT~t zRx8$_2l<~WHXwn*kYWJoVXY!GA#=ZC30hz@6=t3LJ zHUIy3`|jwY?thMfEoVG_(d^T2o)yi#ZntL!uW%MWIq#4;=lIJm@z;clwn!hhYVqdF zqLS7Rrb)v=^Gl8o<4HI%(o6p)xy!skG@T2L*YROtlukEpbPd> zidBdp_XkBEVsQSbSce|upH^%@0)=N314uusRfHyFI*KJ|f$=9r7usMxr&xv%vVT_e zpaa(PiWTUBy;iXb5#;`&=tB(73yO8n+6!bisaGu?i97{-NkY49-TyI`km_j$#86D7>o} zK)R<@geGMEsaS#*82?gqp$+DHsa=jd=j{0>UOF`86mQD(GPz2Z{|y#LB{$(ch4j!AIv>IwgwGgv=Pl z612eRS9GBb=73@uLdb5R=s^dpv|(GPz z&Wa64pkOElklsbB2u;X*La_ubFm_dRp$+D4ie(5PySt(X9kBLLtUwp+PbyX+f}E-7 zLk!NIigoBgew<OznShc4}&E_3HlJM_yaef7JZcwAzLKz)rPymJb-U?WPWl g9hvuL|C8mEJ#xTV0}IF3`tKSTH!{3zVAqKs0)794p#T5? delta 5815 zcmY+|d$be<0mt!sxwlPA7hjDQxr*orC=(ElnzpFXge9YCj*>Q^=unxPiEL)MYUv_s zt9fHqQ@0{pUpR@_Tm{+?9}|RpZ$IJoY}u-&d#n` zx67J!yIf=Ky~0eA7dAgIXY0^)PZ{sMYd>_)wi};5Dr{Z9;Gi3x-*ffQGI!#vp)FI! z5A8i=yXCjeI&RL;d54W3dj78MmrsbU-s``gY*=&W2|M)l_4W6qqtpHot1sB2j;(GU z+kawzU)9;C|D+LW&;xgzVjWWO_En4^v!9j^F=S1}02*NIuULR453(2fpvsp8QNeUsaSyy4}cZOmeQt&>j7(vF- z@*#%o=M)2IfH70CFv9HrxlHDdynp`~T(s|o_3O&cc@N%b&2Tmbm1%3A8GL#EKJ8UU ztXg@;T61H3VRY`Li{?!{>x3EU1!Hm>maaTt?zmf=t&5L4ZS9?x1xxy>xuf+hMM%K> zykZGjV0}Tc3~jKFQLI1*^0O2}=z`-a)}ROOv5Iv_!8=Ydg3K4Se25`?ykYlRK5W3*ZR;)n}+%GHEAqDRg#RxK|YWWaD z_A813G{Eo`3($nzR~3tpfH_C81TC;mQ!GOp?9&x1(1HA1#SpsSoS|5Q9=K;J)*%Hi zP>dimPs@iGvR_jSpaI6$6${XW+&2`9kbrrXVhLJceN(XvZLrT)tUw3y1;r4$;CxH5 z20d`kQLIA>-nSJa$egR?Lk!vZiUBmhI8U(vO~@@!EJ6ZiQLzLqu)d>MhBnyeD^{Qb z`R^)*&;{oL#TxX${hneSQt-a77(wPjEgxdYmJ|bMfN_yx0h*AzSg{BRn3pJ)pas?s z6wA;C`-h4Z=s^Bb#SpsST&7rq9=K)2I;7w&RE!{Vxt0$xWEUw0&;a8K#R4=Tcco$x z5-_h)EI|vbA1Rih4R%Gb0v*U-tr$WVoNE+o&;$3!igifAyH+uR%#fB3F=T(D7(fGz z#fk-JLM~J+LIP%0u>>u!u2U>S8|>>9E6{=bPZdMxf^&mn4SL|-s91*-yqgpw$keoa zh#~tk#Q+*${9LgBP00O1u?Pv6OB74c0_&HGWoUzavtk80kpGop2wiaMiZ$qgdy8Tn zQt)n7j39HHmJcyxZ&wVU0mdDQ1!zKUsbUclFz-|>K?|%%u?%gnf2~-74&?7r4516o zGQ}G7z`a|s4k>uc6(h*pqvb;k+21Gz&;TP=EI<=-!-_>nz`R$n1TC=cQ!GOp>=lX? z=sq?2kvhb>yU!iP>dk+J1rk#$lk9QKm&~5D;A&$xj!ftAp!G`iX~`) z^(VzLw88$fVg)*oZz_h+1?Mk{HRyr+fMOj|@E%l*AoGxx4>4pPRt%s4#%jd^G$FU< z|9{@TJ@O>@{xP_5!S0#!SLcH16IP9$eZ{8!9rl_!ZMb^a%`;cMG=225dz?J)@I|X` zJ7(U&FK#>az$Is0djAvmO=>=5JwEA;E#vNe?x|Ua_EnRS(~mqxnu#bu3#>;J%g_e< zQN;>$Ape+R2wiX(Z7BxO0OKje0yH7_v|Qzr58Sq59a8YtD@KrcUdx9VvM(qG&;a8_#R4=T z_mW}}5-?v@EI|vbR}{<82D_tJfez&VrWisOoDGUK=z+UYu?{JCuPR26c}>fQ7_xs? z44?tV>xu;)h#|XGF@Odb?5u3{P5V85qWfez&VsTe{RoK&#}J#hb}Scgd97ypg%2@gM=1u- z0AoP008PjZDi$FD^8<<{Xn~bcEJGXY4=Prm1NrR~L+FCDysaR*WFC zgO(35WOq~ypaDi!u>eiTjaDo|0_IMNC1`=Qvtk+AVDF+>fez$%RScmE&Tfh|=z;qY z#X6+m8Hy2PcGvPDhU^}S0W`q)sA2({ko%Zo5fU)RD3+iF*2fjg&<1-?#R_yFpHmE> z3(j7OHRyr6w_+Vq@Wv`ekl9DehZwTs6a#30v9DqQnvmO1u?Pv6reX)n&^D#tgrD<-k#=jf```!QHA`77iNKoemk? get6F71FMVuQ-&v Date: Thu, 11 Apr 2024 22:25:03 +0100 Subject: [PATCH 088/132] test: inherit WithdrawHooks_Integration_Concrete_Test into Lockup contracts --- .../lockup-dynamic/LockupDynamic.t.sol | 17 ++++++++++++++++- .../concrete/lockup-linear/LockupLinear.t.sol | 15 +++++++++++++++ .../lockup-tranched/LockupTranched.t.sol | 17 ++++++++++++++++- .../lockup/withdraw-hooks/withdrawHooks.t.sol | 18 +++++++++--------- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index dfb65c75d..b19fbe742 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -27,8 +27,9 @@ import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce. import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; +import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -387,6 +388,20 @@ contract Withdraw_LockupDynamic_Integration_Concrete_Test is } } +contract WithdrawHooks_LockupDynamic_Integration_Concrete_Test is + LockupDynamic_Integration_Concrete_Test, + WithdrawHooks_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupDynamic_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) + { + LockupDynamic_Integration_Concrete_Test.setUp(); + WithdrawHooks_Integration_Concrete_Test.setUp(); + } +} + contract WithdrawMax_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index 3cb11c643..e61e14aa2 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -29,6 +29,7 @@ import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -387,6 +388,20 @@ contract Withdraw_LockupLinear_Integration_Concrete_Test is } } +contract WithdrawHooks_LockupLinear_Integration_Concrete_Test is + LockupLinear_Integration_Concrete_Test, + WithdrawHooks_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupLinear_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) + { + LockupLinear_Integration_Concrete_Test.setUp(); + WithdrawHooks_Integration_Concrete_Test.setUp(); + } +} + contract WithdrawMax_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol index 2d0119b96..8e8e547a7 100644 --- a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -27,8 +27,9 @@ import { Renounce_Integration_Concrete_Test } from "../lockup/renounce/renounce. import { SetNFTDescriptor_Integration_Concrete_Test } from "../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; import { StatusOf_Integration_Concrete_Test } from "../lockup/status-of/statusOf.t.sol"; import { TransferFrom_Integration_Concrete_Test } from "../lockup/transfer-from/transferFrom.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; import { WasCanceled_Integration_Concrete_Test } from "../lockup/was-canceled/wasCanceled.t.sol"; +import { Withdraw_Integration_Concrete_Test } from "../lockup/withdraw/withdraw.t.sol"; +import { WithdrawHooks_Integration_Concrete_Test } from "../lockup/withdraw-hooks/withdrawHooks.t.sol"; import { WithdrawMax_Integration_Concrete_Test } from "../lockup/withdraw-max/withdrawMax.t.sol"; import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from "../lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; @@ -394,6 +395,20 @@ contract Withdraw_LockupTranched_Integration_Concrete_Test is } } +contract WithdrawHooks_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + WithdrawHooks_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, WithdrawHooks_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + WithdrawHooks_Integration_Concrete_Test.setUp(); + } +} + contract WithdrawMax_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, WithdrawMax_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol index 55268ccaf..27c0157c6 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -31,7 +31,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make `unknownCaller` the caller in this test. - changePrank({ msgSender: unknownCaller }); + resetPrank({ msgSender: unknownCaller }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -69,11 +69,11 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodRecipient) }); + resetPrank({ msgSender: address(goodRecipient) }); lockup.approve({ to: users.operator, tokenId: streamId }); // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -111,7 +111,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make the sender the caller in this test. - changePrank({ msgSender: address(goodSender) }); + resetPrank({ msgSender: address(goodSender) }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -150,7 +150,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); // Make the recipient the caller in this test. - changePrank({ msgSender: address(goodRecipient) }); + resetPrank({ msgSender: address(goodRecipient) }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -190,7 +190,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Make unknownCaller the caller in this test. - changePrank({ msgSender: unknownCaller }); + resetPrank({ msgSender: unknownCaller }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -217,11 +217,11 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodSender) }); + resetPrank({ msgSender: address(goodSender) }); lockup.approve({ to: users.operator, tokenId: streamId }); // Make the operator the caller in this test. - changePrank({ msgSender: users.operator }); + resetPrank({ msgSender: users.operator }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -244,7 +244,7 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); // Approve the operator to handle the stream. - changePrank({ msgSender: address(goodSender) }); + resetPrank({ msgSender: address(goodSender) }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); From a551f4180b1c55905f6ca2baef4cc45c151aceb0 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 12 Apr 2024 19:15:32 +0100 Subject: [PATCH 089/132] docs: update security assumptions --- SECURITY.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 151302b1f..0069de713 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -45,7 +45,8 @@ Vulnerabilities contingent upon the occurrence of any of the following also are Sablier V2 Core has been developed with a number of technical assumptions in mind. For a disclosure to qualify as a vulnerability, it must adhere to these assumptions as well: -- The immutable variable `MAX_SEGMENT_COUNT` has a low value that cannot lead to an overflow of the block gas limit. +- The immutable variables `MAX_SEGMENT_COUNT` and `MAX_TRANCHE_COUNT` have values that cannot lead to an overflow of the + block gas limit. - The total supply of any ERC-20 token remains below 2128 - 1, i.e. `type(uint128).max`. - The `transfer` and `transferFrom` methods of any ERC-20 token strictly reduce the sender's balance by the transfer amount and increase the recipient's balance by the same amount. In other words, tokens that charge fees on transfers From a78202d730c0e2196bdb20d4a67965166bf629d7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 13 Apr 2024 12:04:16 +0100 Subject: [PATCH 090/132] docs: fix typo --- shell/deploy-multi-chain.sh | 2 +- src/SablierV2LockupDynamic.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index c02d55c26..1b7e246e2 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -86,7 +86,7 @@ WITH_GAS_PRICE=false # Flag for all chains ON_ALL_CHAINS=false -# Flag for displaying deployement command +# Flag for displaying deployment command READ_ONLY=false # Flag to enter interactive mode in case .env.deployment not found or --interactive is provided diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 13a28d69d..801b44b51 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -277,7 +277,7 @@ contract SablierV2LockupDynamic is } } - /// @dev Calculates the streamed amount for a a stream with one segment. Normalization to 18 decimals is not + /// @dev Calculates the streamed amount for a stream with one segment. Normalization to 18 decimals is not /// needed because there is no mix of amounts with different decimals. function _calculateStreamedAmountForOneSegment(uint256 streamId) internal view returns (uint128) { unchecked { From 389b6a86ab705c561ec4212cc0e2c92f1892fa85 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sun, 14 Apr 2024 14:26:30 +0100 Subject: [PATCH 091/132] test: fix NFTDescriptor fork test (#899) * test: fix NFTDescriptor fork test * test: remove abstract from NFTDescriptor_Fork_Test * test: different expect call * test: remove duplicate import --------- Co-authored-by: Paul Razvan Berg --- test/fork/NFTDescriptor.t.sol | 95 +++++++++++++++++++++++++---------- test/fork/assets/DAI.t.sol | 3 -- test/fork/assets/EURS.t.sol | 3 -- test/fork/assets/SHIB.t.sol | 3 -- test/fork/assets/USDC.t.sol | 3 -- test/fork/assets/USDT.t.sol | 3 -- 6 files changed, 69 insertions(+), 41 deletions(-) diff --git a/test/fork/NFTDescriptor.t.sol b/test/fork/NFTDescriptor.t.sol index 31c096f4c..89912d632 100644 --- a/test/fork/NFTDescriptor.t.sol +++ b/test/fork/NFTDescriptor.t.sol @@ -8,12 +8,19 @@ import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.so import { Fork_Test } from "./Fork.t.sol"; -abstract contract NFTDescriptor_Fork_Test is Fork_Test { +contract NFTDescriptor_Fork_Test is Fork_Test { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + IERC20 internal constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); + address internal constant DAI_HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14; + /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset, address holder) Fork_Test(asset, holder) { } + constructor() Fork_Test(DAI, DAI_HOLDER) { } /*////////////////////////////////////////////////////////////////////////// MODIFIERS @@ -45,71 +52,107 @@ abstract contract NFTDescriptor_Fork_Test is Fork_Test { TEST FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v2.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierV2LockupDynamic.tokenURI}. + /// - The test would fail if the call to {ISablierV2LockupDynamic.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. function testForkFuzz_TokenURI_LockupDynamic_V2_0(uint256 streamId) external loadDeployments_V2_0 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); - string memory tokenURIBefore = lockupDynamic.tokenURI(streamId); - // Set the new NFT descriptor for the previous version of Lockup Dynamic. resetPrank({ msgSender: lockupDynamic.admin() }); lockupDynamic.setNFTDescriptor(nftDescriptor); - string memory tokenURIAfter = lockupDynamic.tokenURI(streamId); + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupDynamic, streamId)), + count: 1 + }); - // Assert that the token URI has not changed. - assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + // Generate the token URI using the new NFT Descriptor. + lockupDynamic.tokenURI(streamId); } - /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v2.1. + /// + /// Checklist: + /// - It should expect a call to {ISablierV2LockupDynamic.tokenURI}. + /// - The test would fail if the call to {ISablierV2LockupDynamic.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. function testForkFuzz_TokenURI_LockupDynamic_V2_1(uint256 streamId) external loadDeployments_V2_1 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); - string memory tokenURIBefore = lockupDynamic.tokenURI(streamId); - // Set the new NFT descriptor for the previous version of Lockup Dynamic. resetPrank({ msgSender: lockupDynamic.admin() }); lockupDynamic.setNFTDescriptor(nftDescriptor); - string memory tokenURIAfter = lockupDynamic.tokenURI(streamId); + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupDynamic, streamId)), + count: 1 + }); - // Assert that the token URI has not changed. - assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + // Generate the token URI using the new NFT Descriptor. + lockupDynamic.tokenURI(streamId); } - /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v2.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierV2LockupLinear.tokenURI}. + /// - The test would fail if the call to {ISablierV2LockupLinear.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. function testForkFuzz_TokenURI_LockupLinear_V2_0(uint256 streamId) external loadDeployments_V2_0 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); - string memory tokenURIBefore = lockupLinear.tokenURI(streamId); - // Set the new NFT descriptor for the previous version of Lockup Linear. resetPrank({ msgSender: lockupLinear.admin() }); lockupLinear.setNFTDescriptor(nftDescriptor); - string memory tokenURIAfter = lockupLinear.tokenURI(streamId); + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupLinear, streamId)), + count: 1 + }); - // Assert that the token URI has not changed. - assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + // Generate the token URI using the new NFT Descriptor. + lockupLinear.tokenURI(streamId); } - /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v2.1. + /// + /// Checklist: + /// - It should expect a call to {ISablierV2LockupLinear.tokenURI}. + /// - The test would fail if the call to {ISablierV2LockupLinear.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. function testForkFuzz_TokenURI_LockupLinear_V2_1(uint256 streamId) external loadDeployments_V2_1 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); - string memory tokenURIBefore = lockupLinear.tokenURI(streamId); - // Set the new NFT descriptor for the previous version of Lockup Linear. resetPrank({ msgSender: lockupLinear.admin() }); lockupLinear.setNFTDescriptor(nftDescriptor); - string memory tokenURIAfter = lockupLinear.tokenURI(streamId); + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupLinear, streamId)), + count: 1 + }); - // Assert that the token URI has not changed. - assertEq(tokenURIBefore, tokenURIAfter, "incompatible token URI"); + // Generate the token URI using the new NFT Descriptor. + lockupLinear.tokenURI(streamId); } } diff --git a/test/fork/assets/DAI.t.sol b/test/fork/assets/DAI.t.sol index 6dfa4e3a3..6bf507732 100644 --- a/test/fork/assets/DAI.t.sol +++ b/test/fork/assets/DAI.t.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; -import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev A typical 18-decimal ERC-20 asset with a normal total supply. IERC20 constant ASSET = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -17,5 +16,3 @@ contract DAI_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) { contract DAI_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract DAI_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } - -contract DAI_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/EURS.t.sol b/test/fork/assets/EURS.t.sol index 4b3a621e1..c27504e63 100644 --- a/test/fork/assets/EURS.t.sol +++ b/test/fork/assets/EURS.t.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; -import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with 2 decimals. IERC20 constant ASSET = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8); @@ -17,5 +16,3 @@ contract EURS_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract EURS_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract EURS_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } - -contract EURS_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/SHIB.t.sol b/test/fork/assets/SHIB.t.sol index a70933cbf..6d2f9dcbd 100644 --- a/test/fork/assets/SHIB.t.sol +++ b/test/fork/assets/SHIB.t.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; -import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with a large total supply. IERC20 constant ASSET = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); @@ -17,5 +16,3 @@ contract SHIB_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract SHIB_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract SHIB_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } - -contract SHIB_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDC.t.sol b/test/fork/assets/USDC.t.sol index 5e1c8cbbb..f253f779a 100644 --- a/test/fork/assets/USDC.t.sol +++ b/test/fork/assets/USDC.t.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; -import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant ASSET = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); @@ -17,5 +16,3 @@ contract USDC_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract USDC_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract USDC_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } - -contract USDC_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } diff --git a/test/fork/assets/USDT.t.sol b/test/fork/assets/USDT.t.sol index 631827d3c..d2d803eec 100644 --- a/test/fork/assets/USDT.t.sol +++ b/test/fork/assets/USDT.t.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; -import { NFTDescriptor_Fork_Test } from "../NFTDescriptor.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant ASSET = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); @@ -17,5 +16,3 @@ contract USDT_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(ASSET, HOLDER) contract USDT_LockupLinear_Fork_Test is LockupLinear_Fork_Test(ASSET, HOLDER) { } contract USDT_LockupTranched_Fork_Test is LockupTranched_Fork_Test(ASSET, HOLDER) { } - -contract USDT_NFTDescriptor_Fork_Test is NFTDescriptor_Fork_Test(ASSET, HOLDER) { } From e3f6da63bce758ef8f65b9a6192582c04a5efcb6 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sun, 14 Apr 2024 17:49:01 +0100 Subject: [PATCH 092/132] ci: add `staging` and `staging-blast` to `ci.yml` (#901) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aff2f0071..d7c26c117 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,8 @@ on: push: branches: - "main" + - "staging" + - "staging-blast" jobs: lint: From 9657fbd0a77821a088b34d460dd1117e5600bb43 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 17 Apr 2024 18:58:54 +0100 Subject: [PATCH 093/132] build: update bun lockfile --- bun.lockb | Bin 43200 -> 43200 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index 11a133d47dd94cfb065836d9c538241f1304cae3..1ae6ec4e0af7e7cd98c4578f311e26cc0e70ba4e 100755 GIT binary patch delta 712 zcmW;ADQv<307l_Jvd&djHkm=O?(Xiglil6H<&elqWMw6W1j!t-S+bMkZ|-s$u(MeANCz#Q$m zP9F=bJm`ctL+4Q^!a2H6Is;sw_pCF*CDvbb#<)WNRcC^0Y`^KmX!zJ0KS2Y@CIA2c delta 708 zcmW;ADQv<307l^r(YZ=wGgZa9ySuxCjosY=E3Oh*Sy@?$S%M@}NU~%}C1Iwr38oT> zL?X%dKlA0~jVG1yr1JeyTV44KYVCiAXl$rM%+PdnIyl1WrcQ)8T3b3X7HDtlBv_)e zqm$wk-Cdn7&d}S_>ERq3`#ODGpzrDoaEZZz&Jc}5b%+_7M>-uGVf9!i!W^v=ofr$W zPjwP3(K*veaf+^|)5RHj=Q=%{W8*@nj|=oKbq2V^;7VtRMqM3ZhUT?S2S-@F(TOle ztDzHPf%dIVf+ae4Iw?-kz1QjD47~@P9?r4xsME&<`cFCoTw?I7GepBzhnS)HqSL_< iR$p}@%+Y$&iLpTYT_?d3ou*FOY=8c))qmDoU#&lV<;M#E From 02a3900e9fcedfdb6c7700821faa526b539f86e4 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 23 Apr 2024 10:27:16 +0100 Subject: [PATCH 094/132] build: replace ffi with stdJson for salt creation (#907) * build: replace ffi with stdJson for salt creation * chore: capitalize StdJson import --- foundry.toml | 5 ++--- script/Base.s.sol | 17 ++++++----------- test/utils/BaseScript.t.sol | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/foundry.toml b/foundry.toml index 1a693ed6d..14cc8ac18 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,10 +3,10 @@ bytecode_hash = "none" emv_version = "paris" extra_output = ["storageLayout"] - ffi = true fs_permissions = [ { access = "read", path = "./out" }, - { access = "read", path = "./out-optimized" }, + { access = "read", path = "./out-optimized"}, + { access = "read", path = "package.json"}, { access = "read-write", path = "./cache" }, ] gas_reports = [ @@ -78,7 +78,6 @@ # Test the optimized contracts without re-compiling them [profile.test-optimized] - ffi = true src = "test" [doc] diff --git a/script/Base.s.sol b/script/Base.s.sol index 2747791f4..2e662194f 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -7,9 +7,11 @@ import { Sphinx } from "@sphinx-labs/contracts/SphinxPlugin.sol"; import { console2 } from "forge-std/src/console2.sol"; import { Script } from "forge-std/src/Script.sol"; +import { stdJson } from "forge-std/src/StdJson.sol"; contract BaseScript is Script, Sphinx { using Strings for uint256; + using stdJson for string; /// @dev The Avalanche chain ID. uint256 internal constant AVALANCHE_CHAIN_ID = 43_114; @@ -91,18 +93,11 @@ contract BaseScript is Script, Sphinx { /// /// Notes: /// - The salt format is "ChainID , Version ". - /// - The version is obtained from `package.json` using the `ffi` cheatcode: - /// https://book.getfoundry.sh/cheatcodes/ffi - /// - Requires the `jq` CLI installed: https://jqlang.github.io/jq/ - function constructCreate2Salt() public returns (bytes32) { + /// - The version is obtained from `package.json`. + function constructCreate2Salt() public view returns (bytes32) { string memory chainId = block.chainid.toString(); - string[] memory inputs = new string[](4); - inputs[0] = "jq"; - inputs[1] = "-r"; - inputs[2] = ".version"; - inputs[3] = "./package.json"; - bytes memory result = vm.ffi(inputs); - string memory version = string(result); + string memory json = vm.readFile("package.json"); + string memory version = json.readString(".version"); string memory create2Salt = string.concat("ChainID ", chainId, ", Version ", version); console2.log("The CREATE2 salt is \"%s\"", create2Salt); return bytes32(abi.encodePacked(create2Salt)); diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index d5b9bfda4..65f8585fa 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -15,7 +15,7 @@ contract BaseScript_Test is StdAssertions { baseScript = new BaseScript(); } - function test_ConstructCreate2Salt() public { + function test_ConstructCreate2Salt() public view { string memory chainId = block.chainid.toString(); string memory version = "1.1.2"; string memory salt = string.concat("ChainID ", chainId, ", Version ", version); From 350fcceddd60736193b71f576093b51f31d7b1e5 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 3 May 2024 17:35:33 +0100 Subject: [PATCH 095/132] refactor: `Range` struct to `Timestamp` struct (#913) * refactor: Range struct to Timestamp struct * chore: update gas snapshot * test: update precompiles * refactor: rename timestamp to timestamps * refactor: rename Timestamp to Timestamps * style: correct bad formated natspec --------- Co-authored-by: andreivladbrg --- .gas-snapshot | 873 +++++++++--------- precompiles/Precompiles.sol | 6 +- src/SablierV2LockupDynamic.sol | 24 +- src/SablierV2LockupLinear.sol | 52 +- src/SablierV2LockupTranched.sol | 24 +- src/interfaces/ISablierV2LockupDynamic.sol | 16 +- src/interfaces/ISablierV2LockupLinear.sol | 29 +- src/interfaces/ISablierV2LockupTranched.sol | 16 +- src/libraries/Helpers.sol | 22 +- src/types/DataTypes.sol | 58 +- test/fork/LockupDynamic.t.sol | 15 +- test/fork/LockupLinear.t.sol | 36 +- test/fork/LockupTranched.t.sol | 11 +- .../createWithDurations.t.sol | 14 +- .../createWithTimestamps.t.sol | 2 +- .../getTimestamps.t.sol} | 12 +- .../get-timestamps/getTimestamps.tree} | 4 +- .../createWithDurations.t.sol | 12 +- .../createWithTimestamps.t.sol | 14 +- .../getTimestamps.t.sol} | 12 +- .../get-timestamps/getTimestamps.tree} | 4 +- .../createWithDurations.t.sol | 14 +- .../createWithTimestamps.t.sol | 2 +- .../getTimestamps.t.sol} | 12 +- .../get-timestamps/getTimestamps.tree} | 4 +- .../lockup-dynamic/createWithDurations.t.sol | 10 +- .../lockup-dynamic/createWithTimestamps.t.sol | 12 +- .../lockup-linear/createWithDurations.t.sol | 12 +- .../lockup-linear/createWithTimestamps.t.sol | 32 +- .../lockup-tranched/createWithDurations.t.sol | 10 +- .../createWithTimestamps.t.sol | 8 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 19 +- .../shared/lockup-linear/LockupLinear.t.sol | 21 +- .../lockup-tranched/LockupTranched.t.sol | 11 +- .../handlers/LockupLinearCreateHandler.sol | 13 +- test/utils/Assertions.sol | 26 +- test/utils/Defaults.sol | 18 +- test/utils/Events.sol | 8 +- 38 files changed, 767 insertions(+), 721 deletions(-) rename test/integration/concrete/lockup-dynamic/{get-range/getRange.t.sol => get-timestamps/getTimestamps.t.sol} (54%) rename test/integration/concrete/{lockup-tranched/get-range/getRange.tree => lockup-dynamic/get-timestamps/getTimestamps.tree} (65%) rename test/integration/concrete/lockup-linear/{get-range/getRange.t.sol => get-timestamps/getTimestamps.t.sol} (54%) rename test/integration/concrete/{lockup-dynamic/get-range/getRange.tree => lockup-linear/get-timestamps/getTimestamps.tree} (65%) rename test/integration/concrete/lockup-tranched/{get-range/getRange.t.sol => get-timestamps/getTimestamps.t.sol} (54%) rename test/integration/concrete/{lockup-linear/get-range/getRange.tree => lockup-tranched/get-timestamps/getTimestamps.tree} (65%) diff --git a/.gas-snapshot b/.gas-snapshot index 23980f0ec..48f3def76 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,118 +1,118 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89728) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80566) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80555) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89750) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80588) +Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80577) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 81703) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11307) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90105) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89997) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14290) Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19526) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19475) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 91971) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82804) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82793) +Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19453) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 91993) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82826) +Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82815) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 83947) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11293) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 82872) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 82797) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14276) Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19512) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19461) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100802) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91635) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91624) +Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19439) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100824) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91657) +Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91646) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 92794) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11337) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90032) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89957) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14320) Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19556) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19505) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 825543) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6315) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32135) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 834301) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12422) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78418) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326169) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 917699) -CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1182497, ~: 1186661) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 605488) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6332) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34328) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 635517) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12436) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80425) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254338) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 718901) -CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 871389, ~: 873499) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 781606) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6354) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41710) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934117) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12458) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87800) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343272) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028209) -CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1187346, ~: 1189529) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 374152) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 357307) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97679) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 359190) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357874) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 72695) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11309) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86904) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63165) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26736) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246553) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 441056, ~: 442191) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 73280, ~: 73354) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 279422) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262552) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 80064) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 264430) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 263119) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 74751) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11298) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79680) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65418) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 28901) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192700) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 318219, ~: 319610) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 75350, ~: 75556) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 363234) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 346311) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 87493) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 348233) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346878) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 82179) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11342) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86840) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74221) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36305) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273654) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 405987, ~: 406220) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 82750, ~: 82693) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5056466) -Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3903481) -Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4104734) -CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 356999) -CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 50, μ: 4078448, ~: 3524013) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 286244) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 281828, ~: 284643) -CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 387388) -CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 50, μ: 4592175, ~: 4807073) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 350001) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 356422) +Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19483) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 825245) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6337) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32154) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 834317) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12441) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78346) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326099) +CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 917533) +CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 1187323, ~: 1187205) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 605322) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6354) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34350) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 635539) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12455) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80386) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254304) +CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 718807) +CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 871449, ~: 873846) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 781440) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6376) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41732) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934139) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12477) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87761) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343238) +CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028115) +CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 1187817, ~: 1189876) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 374065) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 357198) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97570) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 359078) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357765) +Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 72608) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11306) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86793) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63162) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26730) +Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246547) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 439285, ~: 441871) +Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 73205, ~: 73472) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 279367) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262476) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 79988) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 264351) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 263043) +Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 74697) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11295) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79602) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65415) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 28898) +Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192697) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 318154, ~: 319467) +Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 75294, ~: 75561) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 363179) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 346235) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 87417) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 348154) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346802) +Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 82125) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11339) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86762) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74218) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36302) +Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273651) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 403616, ~: 406077) +Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 82722, ~: 82989) +Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5054235) +Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3901281) +Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4102534) +CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 357047) +CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 76, μ: 4638758, ~: 4576850) +CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 286201) +CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 59, μ: 284174, ~: 284666) +CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 387411) +CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 76, μ: 4727005, ~: 4774224) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 350026) +CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 356447) CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 38801) -CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 50, μ: 4240375, ~: 3897903) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 284891) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 291246) +CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 76, μ: 3840986, ~: 4093877) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 284913) +CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 291268) CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_StartTimeLessThanEndTime() (gas: 242528) CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 33024) -CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 50, μ: 397470, ~: 409218) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 377346) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 383767) +CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 74, μ: 401117, ~: 409850) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 377367) +CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 383788) CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41670) -CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 50, μ: 4246517, ~: 4719143) +CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 75, μ: 3975411, ~: 3912867) GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 16028) GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 279107) GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12005) @@ -120,96 +120,96 @@ GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 227792) GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) GetAsset_LockupTranched_Integration_Concrete_Test:test_GetAsset() (gas: 304673) GetAsset_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12013) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 228432) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11413) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 228455) +GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11435) GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 282044) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11637) +GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11659) GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 230681) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) +GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11633) GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 307632) -GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11667) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 281864) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11537) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 230571) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11545) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 307474) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11589) -GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 278092) -GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13036) -GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 227708) -GetRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13228) -GetRange_LockupTranched_Integration_Concrete_Test:test_GetRange() (gas: 303615) -GetRange_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13044) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 15675) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67651) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11436) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 15655) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69889) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11416) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 15683) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78720) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11444) +GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11689) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 281886) +GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11559) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 230593) +GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11567) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 307496) +GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 15697) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67673) +GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11458) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 15677) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69911) +GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11438) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 15705) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78742) +GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11466) GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 311818) GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 301586) GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 306861) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306854) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 346255) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 348111) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306832) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 346191) +GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 348047) GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11935) GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 258782) GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 248283) GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 253558) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253551) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289733) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 291516) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253529) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289702) +GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 291485) GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11921) GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 340410) GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 327152) GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 332427) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 332420) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369718) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 371537) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 332398) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369687) +GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 371506) GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11943) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283532) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13713) -GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 278892) -GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11769) -GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 227571) -GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11749) -GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 304458) -GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11777) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283577) +GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13735) +GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 278914) +GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11791) +GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 227593) +GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11771) +GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 304480) +GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11799) GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 282061) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11801) +GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11823) GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 230746) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11787) +GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11809) GetStartTime_LockupTranched_Integration_Concrete_Test:test_GetStartTime() (gas: 307627) -GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11809) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 276867) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 64268) -GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15755) +GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11831) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 276912) +GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 64313) +GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15777) GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 52571) GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 54618) -GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14524) +GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14546) GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream() (gas: 303573) GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 68952) -GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15753) +GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15775) +GetTimestamps_LockupDynamic_Integration_Concrete_Test:test_GetTimestamps() (gas: 277498) +GetTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12552) +GetTimestamps_LockupLinear_Integration_Concrete_Test:test_GetTimestamps() (gas: 227179) +GetTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12744) +GetTimestamps_LockupTranched_Integration_Concrete_Test:test_GetTimestamps() (gas: 303107) +GetTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12560) GetTranches_LockupTranched_Integration_Concrete_Test:test_GetTranches() (gas: 310004) -GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13519) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356065) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304847) +GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13541) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356043) +GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304825) GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11934) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 359040, ~: 359618) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 306462, ~: 306683) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 275415) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253544) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 359016, ~: 359242) +GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 306500, ~: 306758) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 275393) +GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253522) GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11920) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 278630, ~: 278520) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 255145, ~: 255380) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 357087) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 330413) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 278623, ~: 278432) +GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 255142, ~: 255455) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 357065) +GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 330391) GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11942) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 360154, ~: 360186) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 332001, ~: 331963) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 360235, ~: 360098) +GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 332057, ~: 332324) IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 483969) IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 305109) IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 298835) @@ -222,24 +222,24 @@ IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable() (gas: IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 332234) IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 324435) IsCancelable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 345085) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311529) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299599) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 305439) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 344999) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311551) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299621) +IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 305461) IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 321700) -IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11580) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288614) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258551) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 248354) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 254354) +IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11602) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288561) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258573) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 248376) +IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 254376) IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 254797) -IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11623) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 368598) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 340178) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 325222) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332582) +IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11645) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 368545) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 340200) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 325244) +IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332604) IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 333051) -IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11632) +IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11654) IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 310963) IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 298184) IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) @@ -249,100 +249,100 @@ IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted() (gas: 339577) IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 323772) IsDepleted_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 298544) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 11602) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 247261) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 11623) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 324107) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 11610) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 298690) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11689) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 483824) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 247432) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11732) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 384755) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 324278) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11719) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 533122) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344575) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 298566) +IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 11624) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 247283) +IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 11645) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 324129) +IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 11632) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 298712) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11711) +IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 483846) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 247454) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11754) +IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 384777) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 324300) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11741) +IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 533144) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344467) IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 311040) IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 299017) IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 304957) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 321212) +IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 321190) IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11118) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 288095) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 288020) IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 258046) IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 247756) IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 253866) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 254293) +IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 254271) IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 368035) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 367960) IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 339629) IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 324580) IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 332050) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 332503) +IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 332481) IsWarm_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11126) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 20092) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 19732) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupTranched() (gas: 20496) -MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 911452) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 20114) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 19754) +MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupTranched() (gas: 20518) +MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 947952) RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 311027) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304884) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304862) RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 304855) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311672) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344510) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347729) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 489143) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311717) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344402) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347622) +RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 489144) RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11121) -RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 49760, ~: 64695) +RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 43844, ~: 31437) RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 258007) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253572) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253550) RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 253737) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 255135) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 288004) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 291150) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 390054) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 255180) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 287929) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 291076) +RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 390055) RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 33537, ~: 33714) +RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 33544, ~: 33767) RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 339613) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331795) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331773) RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 331944) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 333077) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367967) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 371149) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538413) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 333122) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367892) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 371075) +RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538414) RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 42343, ~: 42478) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 674450) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 667547) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 279340) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672720) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 668110) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87243) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63573) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24758) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 628608) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 527612) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520677) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 228094) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525842) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 521240) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 80032) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65848) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26936) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 481702) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 750292) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 743357) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 307711) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749898) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743920) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11619) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87148) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74607) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34296) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 702951) +RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 42270, ~: 42531) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 674472) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 667569) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 279362) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672786) +Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 668132) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11633) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87157) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63595) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24780) +Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 628630) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 527634) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520699) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 228116) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525908) +Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 521262) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11641) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79979) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65870) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26958) +Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 481724) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 750314) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 743379) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 307733) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749964) +Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743942) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11641) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87095) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74629) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34318) +Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 702973) SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 15233) SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_DecimalsNotImplemented() (gas: 14011) SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_EOA() (gas: 12384) @@ -351,239 +351,260 @@ SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 6 SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13573) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 549340) SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 15218) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6621165) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2173601) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6621585) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2173921) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6630809) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2183286) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11639) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6641536) +SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2174048) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6641956) +SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2174368) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6651179) +SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2183733) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11661) StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 321826) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311658) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305618) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299673) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 345203) -StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11647) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311680) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305640) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299695) +StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 345117) +StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11669) StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 254225) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258634) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 254497) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 248382) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288693) -StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11669) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258656) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 254519) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 248404) +StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288640) +StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11691) StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf() (gas: 332488) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 340274) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332738) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 325263) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368690) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 340296) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332760) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 325285) +StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368637) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11363) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46712) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 51600) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 243140) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46690) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 51557) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 243119) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20956) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 26320) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 64611) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 26298) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 64589) StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 21041) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 27350) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88316) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 112081) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3527814, ~: 3132657) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3974945, ~: 4117049) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 275320, ~: 269270) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 27328) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88231) +StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111997) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 76, μ: 3429088, ~: 3280853) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 76, μ: 3944273, ~: 4547498) +StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 75, μ: 275057, ~: 269182) StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 29033) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 29011) StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 22523) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29895) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66820) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29919) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66798) StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 23037) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 29550) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 81106) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104765) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 250714, ~: 250611) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 30129, ~: 30364) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 255728, ~: 257888) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 29528) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 81054) +StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104714) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 75, μ: 250415, ~: 249688) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 76, μ: 30089, ~: 30298) +StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 75, μ: 257278, ~: 258128) StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 44651) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35797) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 44607) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35775) StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 30316) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 35680) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 75645) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 35658) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 75623) StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 30423) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36954) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88288) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111949) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 50, μ: 3412261, ~: 3624836) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 50, μ: 3836358, ~: 3850731) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13949) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36932) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88236) +StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111898) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 76, μ: 3763594, ~: 4155368) +StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 76, μ: 3923618, ~: 3973167) +TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13971) TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) -TokenURI_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13932) +TokenURI_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13954) TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) -TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13954) +TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13976) TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 281658) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294710) +TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294732) TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 229833) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 243397) +TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 243419) TransferFrom_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 307376) -TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 320284) +TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 320306) WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12019) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 315725) +WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 315616) WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 299008) WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12040) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 262452) +WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 262376) WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 247728) WasCanceled_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12027) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 342695) +WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 342619) WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 324574) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72267) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14095) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 249967) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 161853) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97659) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 138167, ~: 158647) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74526) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14093) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196166) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 116725) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99964) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 99953, ~: 114536) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83351) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14115) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277083) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 126986) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108745) -WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 111182, ~: 124791) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 358719) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 329120) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 329235) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 332598) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 351465) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 321888) +WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 325497) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 291226) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 261612) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 261748) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 265100) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 283978) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 254387) +WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 258005) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 372130) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 342516) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 342652) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 346004) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 364887) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 335296) +WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 338914) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72289) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14117) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 249989) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 161875) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97681) +WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 133982, ~: 112931) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74548) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14115) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196188) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 116747) +WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99986) +WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 106745, ~: 115227) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83373) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14137) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277105) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 127008) +WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108767) +WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 116105, ~: 125476) WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 138996) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80630) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 120523, ~: 123572) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83249, ~: 83404) +WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80608) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 123460, ~: 124010) +WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 83174, ~: 83318) WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 80273) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 82915) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 78556, ~: 78693) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 85520, ~: 85689) +WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 82893) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 78577, ~: 78666) +WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 85432, ~: 85603) WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax() (gas: 91922) -WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 91755) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 88695, ~: 88993) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 94402, ~: 94529) +WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 91733) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 88760, ~: 88907) +WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 94326, ~: 94443) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73486) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20712) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124801) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124779) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 82981) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 274573) +WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 274574) WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6560) -WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 2704176, ~: 2704701) +WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 2705346, ~: 2705247) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 75652) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20614) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 109270) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 109248) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 85147) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 227818) +WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 227852) WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6549) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 1995688, ~: 1995633) +WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 1995659, ~: 1995523) WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 84497) WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20700) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124147) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124125) WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 93992) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 251699) +WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 251733) WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6608) -WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 50, μ: 2887130, ~: 2887100) +WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 2887114, ~: 2886990) Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19851) Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 65278) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 355910) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113737) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 84219) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 85125) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 355888) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113693) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 84175) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 85081) Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 69772) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297883) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355343) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 109286) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 376688) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355941) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323308) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297846) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 297368) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85854) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 129471) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 126142, ~: 103351) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 149197, ~: 149197) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3930319, ~: 3826320) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 162571, ~: 162747) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 107201, ~: 107201) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297839) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355321) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 109264) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 376666) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355919) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323286) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297802) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 297324) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85810) +Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 129362) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 75, μ: 131584, ~: 103286) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 149175, ~: 149175) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 76, μ: 4168893, ~: 4262966) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 75, μ: 162688, ~: 162616) +Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 107201, ~: 107201) Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19826) Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67517) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 274768) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 96056) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 66533) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 67439) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 274746) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 96012) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 66489) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 67395) Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 71955) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 230368) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 274199) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 77955) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 281870) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 274797) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 242127) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 230332) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229854) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 68168) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 111795) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 106092, ~: 106044) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 117877, ~: 117877) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 145053, ~: 144905) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 75848, ~: 75848) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 230324) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 274177) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 77933) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 281848) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 274775) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 242105) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 230288) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229810) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 68124) +Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 111719) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 76, μ: 106164, ~: 105979) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 117855, ~: 117855) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 76, μ: 144928, ~: 144763) +Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 75848, ~: 75848) Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19833) Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 76283) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 357101) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 103451) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73928) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74834) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 357079) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 103407) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73884) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74790) Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 79361) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 311290) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 356532) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 86758) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 365577) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 357130) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 324426) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 311254) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310776) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 75563) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 119282) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 117380, ~: 117109) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 126674, ~: 126674) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 152488, ~: 152396) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 50, μ: 3656828, ~: 3369659) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 50, μ: 84673, ~: 84673) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 311246) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 356510) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 86736) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 365555) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 357108) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 324404) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 311210) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310732) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 75519) +Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 119206) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 75, μ: 117647, ~: 117488) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 126652, ~: 126652) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 75, μ: 152434, ~: 152254) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 76, μ: 3694638, ~: 3705862) +Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 84673, ~: 84673) WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12001) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 347152) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316711) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 306125) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 347109) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316668) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 306103) WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 312711) WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 302873) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 309163) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 347262) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 349434) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 321569, ~: 302618) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 285304, ~: 278607) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 309141) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 347177) +WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 349327) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 76, μ: 319238, ~: 302486) +WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 76, μ: 289334, ~: 278476) WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11965) WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 246950) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 254430) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 254408) WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 259672) WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 249588) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 256071) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290715) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292814) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277929) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 474838, ~: 475697) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 254609, ~: 254885) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 450939, ~: 451827) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 256049) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290663) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292740) +WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277907) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 76, μ: 474541, ~: 473581) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 76, μ: 254619, ~: 254819) +WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 76, μ: 450630, ~: 449585) WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12009) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364842) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 338486) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 333040) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364800) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 338398) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 333018) WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 341300) WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 329788) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 336256) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370722) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372857) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 329755, ~: 329375) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 304445, ~: 304467) \ No newline at end of file +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 336234) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370670) +WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372783) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 76, μ: 329511, ~: 329114) +WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 76, μ: 304390, ~: 304292) \ No newline at end of file diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 2aa247bf8..506639361 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,11 +26,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f19620059f23881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556155f090816200040282396080518161395e015260a051818181610c9f0152613a250152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461268e57508063027b67441461266b57806306fdde03146125a5578063081812fc14612587578063095ea7b3146124865780631400ecec146123e15780631c1cdd4c1461237b5780631e99d5691461235d57806323b872dd1461234657806331df3d481461223a57806340e58ee514611f80578063425d30dd14611f2c57806342842e0e14611ef257806342966c6814611d1a5780634426757014611cf35780634857501f14611c7d5780634869e12d14611c415780634cc55e1114611b4657806354c02292146118c15780636352211e146118925780636d0cee751461189257806370a082311461182157806375829def1461178f5780637cad6cd1146116945780637de6b1db1461147c5780638659c27014611125578063894e9a0d14610d985780638f69b99314610d155780639067b67714610cc25780639188ec8414610c8757806395d89b4114610b77578063a22cb46514610aba578063a80fc07114610a65578063ad35efd414610a02578063b2564569146109ae578063b637b86514610951578063b88d4fde146108c8578063b8a3be6614610891578063b971302a1461083f578063bc2be1be146107ec578063c156a11d146106a8578063c87b56dd14610593578063cc364f48146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d576102746127bb565b6044356001600160801b038116810361029d5761029b91610293613954565b60043561335b565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a26127bb565b6103ab826141fa565b91612fa9565b3461029d57604036600319011261029d576103ca6127a5565b6103d26127bb565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141fa565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d57602036600319011261029d576004356000602060405161051d816128f5565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff825191610560836128f5565b818160a01c16835260c81c166020820152610591825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d5760208060031936011261029d57600435906105b2826136f1565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561069c57600092610623575b5061061f604051928284938452830190612780565b0390f35b9091503d806000833e6106368183612942565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d57805161066b81612964565b926106796040519485612942565b81845284828401011161029d576106959184808501910161275d565b908261060a565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d576004356106c46127bb565b6106cc613954565b81600052600960205260ff60016040600020015460a81c16156107d5578160005260036020526001600160a01b038060406000205416918233036107b657610713846141fa565b6001600160801b0381166107a5575b508181161561078d578361073591613813565b908116806107555760248460405190637e27328960e01b82526004820152fd5b820361075d57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b6107b0908486612fa9565b84610722565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108e16127a5565b6108e96127bb565b6064359167ffffffffffffffff831161029d573660238401121561029d5782600401359161091683612964565b926109246040519485612942565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a60205261061f61099a6040600020612da5565b60405191829160208352602083019061284b565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610a3c9061378c565b6040516005821015610a4f576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610ad36127a5565b6024359081151580920361029d576001600160a01b0316908115610b4657336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610c7d575b6020948585108414610c67578587948686529182600014610c47575050600114610bea575b50610bd692500383612942565b61061f604051928284938452830190612780565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610c2f575050610bd6935082010185610bc9565b80548389018501528794508693909201918101610c18565b60ff191685820152610bd695151560051b8501019250879150610bc99050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610ba4565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610d4f9061378c565b600581101580610a4f5760028214908115610d8b575b8115610d79575b6020826040519015158152f35b9050610a4f5760046020911482610d6c565b5050600381146000610d65565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff8211176110eb576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610e1a612d52565b6101408201520152600435600052600960205260ff60016040600020015460a81c161561110d5760043560005260096020526040600020610eeb600260405192610e6384612925565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612d71565b610120820152610efc60043561378c565b6005811015610a4f57600214611101575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e0850151151561010086015115159160043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff6101808281810110920111176110eb576101609c610ffe9b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612da5565b8282015261061f604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061284b565b634e487b7160e01b600052604160045260246000fd5b60006060820152610f0d565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d5761115790369060040161281a565b90611160613954565b6000915b80831061116d57005b611178838284612cf7565b3592611182613954565b83600052600980865260ff600181816040600020015460a81c161561146557866000528288526040600020828282015460a01c166000146111d55760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c61144d576112018560005260096020526001600160a01b0360406000205416331490565b1561142e5761120f85613714565b92856000528089526112276002604060002001612d71565b936001600160801b03938486511685831610156114165787600052828b5260406000205460f01c16156113fe5780848b8161126c94818a5116031697015116906129b8565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a61134d845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a156113e5575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661132384878a614637565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b611390575b5050505060019150019190611164565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16113d6575b808080611380565b6113df90612911565b856113ce565b898601600160a01b60ff60a01b198254161790556112d5565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d576004359061149a613954565b816000526009815260ff60016040600020015460a81c16156107d5576114bf8261378c565b6005811015610a4f57600481036114e85760248360405190634a5541ef60e01b82526004820152fd5b60038103611508576024836040519063fe19f19f60e01b82526004820152fd5b60021461167c5761152f8260005260096020526001600160a01b0360406000205416331490565b1561165d57816000526009815260ff60406000205460f01c1615611645578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b6115d6575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af1156115aa5761163f90612911565b836115aa565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d578160005416338103611766575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116117505760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d576117a86127a5565b6000546001600160a01b03808216923384036117fa576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b036118426127a5565b1680156118615760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118b06004356136f1565b6001600160a01b0360405191168152f35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d576118fe613954565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611938913691612c28565b9182519161194583612c10565b926119536040519485612942565b808452601f1961196282612c10565b018660005b828110611b305750505064ffffffffff90814216936001600160801b03968761198f826139b0565b515116828a61199d846139b0565b51015116858060406119ae866139b0565b5101511689011690604051926119c3846128d9565b83528b83015260408201526119d7886139b0565b526119e1876139b0565b506001938760015b8a8c878310611aaf5790838b8b611a0281600401612d31565b92611a0f60248301612d31565b92611a1c60448401612d1d565b946064840135946001600160a01b039586811680910361029d57611aa798611a6798611a9c98611a4e60848a01612d45565b9481611a5c60a48c01612d45565b976040519d8e6128bc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612cc8565b6101008201526139d1565b604051908152f35b889385806040611ae38b86611ad38a8e9a611aca828d6139bd565b5151169a6139bd565b51015116946000198901906139bd565b51015116816040611af4888c6139bd565b5101511601169160405193611b08856128d9565b84528301526040820152611b1c828c6139bd565b52611b27818b6139bd565b500188906119e9565b611b38612d52565b828289010152018790611967565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b7890369060040161281a565b9160243590811161029d57611b9190369060040161281a565b9091611b9b613954565b818403611c0a5760005b848110611bae57005b80611c04611bbf6001938886612cf7565b35611bcb838987612cf7565b3560005260036020526001600160a01b0360406000205416611bf6611bf185898b612cf7565b612d1d565b91611bff613954565b61335b565b01611ba5565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161414f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cb98261378c565b6005811015610a4f57600203611cd7575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cca565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d38613954565b816000526009815260ff60016040600020015460a81c16156107d557816000526009815260ff60016040600020015460a01c1615611ec157611d79826140e6565b1561165d5781600052600381526001600160a01b038060406000205416151580611eb9575b80611e9f575b611e87577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e4c575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e3457005b60249060405190637e27328960e01b82526004820152fd5b611e6d85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611de4565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615611da4565b506000611d9e565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f00366127e5565b60405191602083019383851067ffffffffffffffff8611176110eb5761029b9460405260008452612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611f9e613954565b81600052600980825260ff60016040600020015460a81c16156122235782600052808252604060002060ff600182015460a01c16600014611ff15760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61220b576120198360005260096020526001600160a01b0360406000205416331490565b156121ec5761202783613714565b8360005281835261203e6002604060002001612d71565b936001600160801b039182865116838216101561167c578160005283855260ff60406000205460f01c1615611645576120a6818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906129b8565b94826000528481526040600020956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895582169788156121d2575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5087604060002054169788938652600160406000200154169361215b8c8487614637565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b61218d57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121c957005b61029b90612911565b60018101600160a01b60ff60a01b198254161790556120ec565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d57612275613954565b60405191612282836128bc565b61228e826004016127d1565b835261229c602483016127d1565b60208401526122ad60448301612980565b604084015260648201356001600160a01b038116810361029d5760608401526122d8608483016128af565b60808401526122e960a483016128af565b60a08401526122fa60c48301612bfe565b60c084015260e482013590811161029d578101913660238401121561029d57611a9c611aa7926123366020953690602460048201359101612c28565b60e0840152610104369101612cc8565b3461029d5761029b612357366127e5565b916129d1565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576123b59061378c565b6005811015610a4f5780602091159081156123d6575b506040519015158152f35b6001915014826123cb565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c1680612474575b61244b575b50506001600160801b0360405191168152f35b61246d92506001600160801b0360026124679201541691613714565b906129b8565b8280612438565b5060ff600182015460a01c1615612433565b3461029d57604036600319011261029d5761249f6127a5565b6024356124ab816136f1565b33151580612574575b80612546575b6125165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff60406000205416156124ba565b50336001600160a01b03821614156124b4565b3461029d57602036600319011261029d5760206118b0600435612994565b3461029d57600036600319011261029d576040516000600190600154918260011c9160018416918215612661575b6020948585108414610c67578587948686529182600014610c475750506001146126045750610bd692500383612942565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612649575050610bd6935082010185610bc9565b80548389018501528794508693909201918101612632565b92607f16926125d3565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612733575b8115612709575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612702565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126fb565b60005b8381106127705750506000910152565b8181015183820152602001612760565b906020916127998151809281855285808601910161275d565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b82811061286b575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161285d565b3590811515820361029d57565b610120810190811067ffffffffffffffff8211176110eb57604052565b6060810190811067ffffffffffffffff8211176110eb57604052565b6040810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57604052565b610140810190811067ffffffffffffffff8211176110eb57604052565b90601f8019910116810190811067ffffffffffffffff8211176110eb57604052565b67ffffffffffffffff81116110eb57601f01601f191660200190565b35906001600160801b038216820361029d57565b61299d816136f1565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161175057565b906001600160a01b03809116801561078d5760009184835260209160038352604092828486205416151580612bf6575b80612bde575b612bc7578685526003815282848620541694873315159384612b17575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612adf575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612ab15750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b0082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612a4d565b91929380915090612b86575b15612b315790878392612a24565b848887612b4e576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612bab575b80612b235750878252600583523384868420541614612b23565b5085825260068352848220338352835260ff8583205416612b91565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615612a07565b506001612a01565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110eb5760051b60200190565b929192612c3482612c10565b604094612c446040519283612942565b8195848352602080930191606080960285019481861161029d57925b858410612c705750505050505050565b868483031261029d57825190612c85826128d9565b612c8e85612980565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612cb9868801612bfe565b86820152815201930192612c60565b919082604091031261029d57604051612ce0816128f5565b6020808294612cee816127d1565b84520135910152565b9190811015612d075760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612d5f826128d9565b60006040838281528260208201520152565b90604051612d7e816128d9565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612db181612c10565b92604093612dc26040519182612942565b82815280946020809201926000526020600020906000935b858510612de957505050505050565b60018481928451612df9816128d9565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612dda565b9190612e428282856129d1565b803b612e4f575b50505050565b612eab6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612780565b03906020816000938185885af190829082612f41575b5050612ef85782612ed06141ca565b8051919082612ef15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f29575038808080612e49565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612fa1575b81612f5e60209383612942565b81010312612f9d5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612f9a5750903880612ec1565b80fd5b5080fd5b3d9150612f51565b92919092612fb5613954565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133455784885281865260ff6001858a20015460a01c1661332e576001600160a01b0391828216928315613317576001600160801b039384861691821561330057888c5260038a5280888d2054169384831415806132f0575b6132cd5761303b8a6141fa565b878116851161329c57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061306c91614222565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130a190612d71565b9080868301511691818481835116920151166130bc916129b8565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9661326f575b878252855220015416946130ff818988614637565b8a51908152a48033141580613265575b613200575b8233141590816131f5575b816131ea575b50613159575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156131e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16131d7575b85948161312b565b6131e090612911565b386131cf565b8780fd5b905082141538613125565b833b1515915061311f565b803b15613261578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af1613252575b50613114565b61325b90612911565b3861324c565b8880fd5b50803b151561310f565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556130ea565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506132fa8a6140e6565b1561302e565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613345578785815281875260ff6001868320015460a01c166136da576001600160a01b03908185169283156136c3576001600160801b03938486169182156136ac5789845260038b5284898520541694858314158061369c575b613679576134008b838e6133ec8361414f565b9289525260028c8820015460801c906129b8565b87811685116136485750908b8b928387528282528b808820998b838c54169b6002015460801c9061343091614222565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561346590612d71565b8180868301511693818351169201511661347e916129b8565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361361a575b848852825260018c8820015416946134c2818c88614637565b8b51908152a48133141580613610575b6135aa575b5081331415908161359f575b81613594575b5061351c575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613590578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613578575b808061312b565b6135828691612911565b61358c5784613571565b8480fd5b8280fd5b9050811415386134e9565b823b151591506134e3565b813b15612f9a578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16135fc575b506134d7565b61360891929a50612911565b9738806135f6565b50813b15156134d2565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134a9565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136a68b6140e6565b156133d9565b60248a8a519063d2aabcd960e01b82526004820152fd5b602488885190630ff7ee2d60e31b82526004820152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e34575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137825760c81c1611156137705750600a602052600160406000205411600014613767576137649061430e565b90565b6137649061423d565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137b3575050600490565b805460f81c61380c575460a01c64ffffffffff164210613806576137d681613714565b9060005260096020526001600160801b03806002604060002001541691161060001461380157600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613949575b80613931575b61391a579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138e2575b1692836138cc575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a8565b61390386600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138a0565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561383f565b508181161515613839565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398657565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d075760200190565b8051821015612d075760209160051b010190565b906139f36001600160801b0360408401511660206101008501510151906144ed565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140bc5780156140925781518015614068577f00000000000000000000000000000000000000000000000000000000000000008111614037575064ffffffffff6040613a5c846139b0565b51015116811015613fe05750600090819082815184905b808210613f4f575050505064ffffffffff421664ffffffffff8216811015613f0f5750506001600160801b0316808203613ed8575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c0f8951996000198b01906139bd565b51015160c81b169560f01b16911617171717845560005b818110613e06575050600185016007556001600160a01b03602083015116801561078d57613c5c866001600160a01b0392613813565b16613dd557613c876001600160a01b036060840151166001600160801b0383511690309033906145c6565b6001600160801b0360208201511680613da5575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613d9a613d7b60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d248c6128f5565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061284b565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613dcf906001600160a01b036060850151166001600160a01b0361010086015151169033906145c6565b38613c9b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e238160e08701516139bd565b518254680100000000000000008110156110eb5760018101808555811015612d0757600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c26565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613f73906001600160801b03613f6a85886139bd565b51511690614222565b9364ffffffffff806040613f8786856139bd565b51015116941680851115613fa357506001849301909291613a73565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613ff1846139b0565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b03806040842054169283331493841561412b575b5050821561411957505090565b9091506141263392612994565b161490565b60ff929450906040918152600660205281812033825260205220541691388061410c565b8060005260096020526141686002604060002001612d71565b816000526009602052604060002060ff600182015460a01c1660001461419b57506001600160801b039150602001511690565b5460f81c6141ad575061376490613714565b61376491506001600160801b0360408183511692015116906129b8565b3d156141f5573d906141db82612964565b916141e96040519384612942565b82523d6000602084013e565b606090565b613764906142078161414f565b90600052600960205260026040600020015460801c906129b8565b9190916001600160801b038080941691160191821161175057565b64ffffffffff614272600091838352600960205280806040852054818160a01c1693849160c81c160316918142160316614691565b91808252600a602052604082208054156142fa5790829167ffffffffffffffff93526142cc602083205482845260096020526142c76001600160801b03968760026040882001541696879360801c1690614781565b6147ef565b9283136142e25750506142de906148d9565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161433483612925565b8054966101206143ba60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612d71565b94019384528452600a6020526143d1858520612da5565b91849680876143df866139b0565b5101511692828288955b16106144b757509161445d6142c79284888161446298976001600160801b039e8f614414898c6139bd565b5151169d8e9a67ffffffffffffffff602061442f8c846139bd565b5101511699848361444083856139bd565b5101511696508061449c57505050511680925b0316920316614691565b614781565b92831361447b57505061447583916148d9565b16011690565b5160200151929392831692841683101591506144979050575090565b905090565b6144ac92935060001901906139bd565b510151168092614453565b8093986001600160801b0390816144ce8c896139bd565b51511601169801928282808a6144e4888a6139bd565b510151166143e9565b919091604051906144fd826128f5565b600091828152826020820152936001600160801b03928383169182156145a75767016345785d8a000080821161457057506145398591846154a1565b166020870192818452111561455c57509082614557925116906129b8565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906145bb826128f5565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110eb5761463592604052614915565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146359161468c606483612942565b614915565b600160ff1b808214908115614777575b5061474d576000811215614744576146ca816000035b600084121561473d5783600003906149b1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470657600019911813156147005790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149b1565b6146ca816146b7565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146a1565b8061479c575061479757670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146147e95750806147c1575050670de0b6b3a764000090565b670de0b6b3a764000081146147e5576147e0906142c761376493614aab565b614bed565b5090565b91505090565b600160ff1b8082149081156148cf575b506148a557600081121561489c57614828816000035b60008412156148955783600003906154a1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485e57600019911813156147005790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154a1565b61482881614815565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386147ff565b600081126148e45790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614940600080836020829551910182875af16149396141ca565b9084615550565b908151918215159283614989575b5050506149585750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612f9d576020015190811591821503612f9a575038808061494e565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a6d5782851015614a3157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a7b570490565b634e487b7160e01b600052601260045260246000fd5b8015614a7b576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bbc57670de0b6b3a764000092838112614b9957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614b8d57506706f05b59d3b20000905b848213614b615750505050500290565b808391020590671bc16d674ec80000821215614b80575b831d90614b51565b8091950194831d90614b78565b93505093925050020290565b6000199392508015614a7b576ec097ce7bc90715b34b9f10000000000591614acc565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c1c5768033dd1780914b9711419811261380657614c1390600003614bed565b61376490614a91565b680a688906bd8affffff811361547057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615353575b66ff000000000000831661524b575b65ff0000000000831661514b575b64ff000000008316615053575b63ff0000008316614f63575b62ff00008316614e7b575b61ff008316614d9b575b60ff8316614cc4575b02911c60bf031c90565b60808316614d89575b838316614d77575b60208316614d65575b60108316614d53575b60088316614d41575b60048316614d2f575b60028316614d1d575b6001831615614cba576801000000000000000102831c614cba565b6801000000000000000102831c614d02565b6801000000000000000302831c614cf9565b6801000000000000000602831c614cf0565b6801000000000000000b02831c614ce7565b6801000000000000001602831c614cde565b6801000000000000002c02831c614cd5565b6801000000000000005902831c614ccd565b6180008316614e69575b6140008316614e57575b6120008316614e45575b6110008316614e33575b6108008316614e21575b6104008316614e0f575b6102008316614dfd575b610100831615614cb157680100000000000000b102831c614cb1565b6801000000000000016302831c614de1565b680100000000000002c602831c614dd7565b6801000000000000058c02831c614dcd565b68010000000000000b1702831c614dc3565b6801000000000000162e02831c614db9565b68010000000000002c5d02831c614daf565b680100000000000058b902831c614da5565b628000008316614f51575b624000008316614f3f575b622000008316614f2d575b621000008316614f1b575b620800008316614f09575b620400008316614ef7575b620200008316614ee5575b62010000831615614ca7576801000000000000b17202831c614ca7565b680100000000000162e402831c614ec8565b6801000000000002c5c802831c614ebd565b68010000000000058b9102831c614eb2565b680100000000000b172102831c614ea7565b68010000000000162e4302831c614e9c565b680100000000002c5c8602831c614e91565b6801000000000058b90c02831c614e86565b63800000008316615041575b6340000000831661502f575b6320000000831661501d575b6310000000831661500b575b63080000008316614ff9575b63040000008316614fe7575b63020000008316614fd5575b6301000000831615614c9c5768010000000000b1721802831c614c9c565b6801000000000162e43002831c614fb7565b68010000000002c5c86002831c614fab565b680100000000058b90c002831c614f9f565b6801000000000b17217f02831c614f93565b680100000000162e42ff02831c614f87565b6801000000002c5c85fe02831c614f7b565b68010000000058b90bfc02831c614f6f565b6480000000008316615139575b6440000000008316615127575b6420000000008316615115575b6410000000008316615103575b64080000000083166150f1575b64040000000083166150df575b64020000000083166150cd575b640100000000831615614c9057680100000000b17217f802831c614c90565b68010000000162e42ff102831c6150ae565b680100000002c5c85fe302831c6150a1565b6801000000058b90bfce02831c615094565b68010000000b17217fbb02831c615087565b6801000000162e42fff002831c61507a565b68010000002c5c8601cc02831c61506d565b680100000058b90c0b4902831c615060565b658000000000008316615239575b654000000000008316615227575b652000000000008316615215575b651000000000008316615203575b6508000000000083166151f1575b6504000000000083166151df575b6502000000000083166151cd575b65010000000000831615614c83576801000000b17218355102831c614c83565b680100000162e430e5a202831c6151ad565b6801000002c5c863b73f02831c61519f565b68010000058b90cf1e6e02831c615191565b680100000b1721bcfc9a02831c615183565b68010000162e43f4f83102831c615175565b680100002c5c89d5ec6d02831c615167565b6801000058b91b5bc9ae02831c615159565b66800000000000008316615341575b6640000000000000831661532f575b6620000000000000831661531d575b6610000000000000831661530b575b660800000000000083166152f9575b660400000000000083166152e7575b660200000000000083166152d5575b6601000000000000831615614c755768010000b17255775c0402831c614c75565b6801000162e525ee054702831c6152b4565b68010002c5cc37da949202831c6152a5565b680100058ba01fb9f96d02831c615296565b6801000b175effdc76ba02831c615287565b680100162f3904051fa102831c615278565b6801002c605e2e8cec5002831c615269565b68010058c86da1c09ea202831c61525a565b6780000000000000008316615451575b674000000000000000831661543f575b672000000000000000831661542d575b671000000000000000831661541b575b6708000000000000008316615409575b67040000000000000083166153f7575b67020000000000000083166153e5575b670100000000000000831615614c6657680100b1afa5abcbed6102831c614c66565b68010163da9fb33356d802831c6153c3565b680102c9a3e778060ee702831c6153b3565b6801059b0d31585743ae02831c6153a3565b68010b5586cf9890f62a02831c615393565b6801172b83c7d517adce02831c615383565b6801306fe0a31b7152df02831c615373565b5077b504f333f9de648480000000000000000000000000000000615363565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461553f57670de0b6b3a7640000908183101561550857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061558f575080511561556557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155da575b6155a0575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561559856fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f19620059f23881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556155f090816200040282396080518161395e015260a051818181610c050152613a250152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461268e57508063027b67441461266b57806306fdde03146125a5578063081812fc14612587578063095ea7b3146124865780631400ecec146123e15780631c1cdd4c1461237b5780631e99d5691461235d57806323b872dd1461234657806331df3d481461223a57806340e58ee514611f80578063425d30dd14611f2c57806342842e0e14611ef257806342966c6814611d1a5780634426757014611cf35780634857501f14611c7d5780634869e12d14611c415780634cc55e1114611b4657806354c02292146118c157806357404b12146118275780636352211e146117f85780636d0cee75146117f857806370a082311461178757806375829def146116f55780637cad6cd1146115fa5780637de6b1db146113e25780638659c2701461108b578063894e9a0d14610cfe5780638f69b99314610c7b5780639067b67714610c285780639188ec8414610bed57806395d89b4114610add578063a22cb46514610a20578063a80fc071146109cb578063ad35efd414610968578063b256456914610914578063b637b865146108b7578063b88d4fde1461082e578063b8a3be66146107f7578063b971302a146107a5578063bc2be1be14610752578063c156a11d1461060e578063c87b56dd146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d576102746127bb565b6044356001600160801b038116810361029d5761029b91610293613954565b60043561335b565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a26127bb565b6103ab826141fa565b91612fa9565b3461029d57604036600319011261029d576103ca6127a5565b6103d26127bb565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141fa565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d5760208060031936011261029d5760043590610518826136f1565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561060257600092610589575b50610585604051928284938452830190612780565b0390f35b9091503d806000833e61059c8183612942565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d5780516105d181612964565b926105df6040519485612942565b81845284828401011161029d576105fb9184808501910161275d565b9082610570565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d5760043561062a6127bb565b610632613954565b81600052600960205260ff60016040600020015460a81c161561073b578160005260036020526001600160a01b0380604060002054169182330361071c57610679846141fa565b6001600160801b03811661070b575b50818116156106f3578361069b91613813565b908116806106bb5760248460405190637e27328960e01b82526004820152fd5b82036106c357005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b610716908486612fa9565b84610688565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108476127a5565b61084f6127bb565b6064359167ffffffffffffffff831161029d573660238401121561029d5782600401359161087c83612964565b9261088a6040519485612942565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a6020526105856109006040600020612da5565b60405191829160208352602083019061284b565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576109a29061378c565b60405160058210156109b5576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610a396127a5565b6024359081151580920361029d576001600160a01b0316908115610aac57336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610be3575b6020948585108414610bcd578587948686529182600014610bad575050600114610b50575b50610b3c92500383612942565b610585604051928284938452830190612780565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610b95575050610b3c935082010185610b2f565b80548389018501528794508693909201918101610b7e565b60ff191685820152610b3c95151560051b8501019250879150610b2f9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610b0a565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610cb59061378c565b6005811015806109b55760028214908115610cf1575b8115610cdf575b6020826040519015158152f35b90506109b55760046020911482610cd2565b5050600381146000610ccb565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff821117611051576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610d80612d52565b6101408201520152600435600052600960205260ff60016040600020015460a81c16156110735760043560005260096020526040600020610e51600260405192610dc984612925565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612d71565b610120820152610e6260043561378c565b60058110156109b557600214611067575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e0850151151561010086015115159160043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff610180828181011092011117611051576101609c610f649b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612da5565b82820152610585604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061284b565b634e487b7160e01b600052604160045260246000fd5b60006060820152610e73565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d576110bd90369060040161281a565b906110c6613954565b6000915b8083106110d357005b6110de838284612cf7565b35926110e8613954565b83600052600980865260ff600181816040600020015460a81c16156113cb57866000528288526040600020828282015460a01c1660001461113b5760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c6113b3576111678560005260096020526001600160a01b0360406000205416331490565b156113945761117585613714565b928560005280895261118d6002604060002001612d71565b936001600160801b039384865116858316101561137c5787600052828b5260406000205460f01c16156113645780848b816111d294818a5116031697015116906129b8565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a6112b3845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a1561134b575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661128984878a614637565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b6112f6575b50505050600191500191906110ca565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161133c575b8080806112e6565b61134590612911565b85611334565b898601600160a01b60ff60a01b1982541617905561123b565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d5760043590611400613954565b816000526009815260ff60016040600020015460a81c161561073b576114258261378c565b60058110156109b5576004810361144e5760248360405190634a5541ef60e01b82526004820152fd5b6003810361146e576024836040519063fe19f19f60e01b82526004820152fd5b6002146115e2576114958260005260096020526001600160a01b0360406000205416331490565b156115c357816000526009815260ff60406000205460f01c16156115ab578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b61153c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af115611510576115a590612911565b83611510565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d5781600054163381036116cc575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116116b65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d5761170e6127a5565b6000546001600160a01b0380821692338403611760576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b036117a86127a5565b1680156117c75760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118166004356136f1565b6001600160a01b0360405191168152f35b3461029d57602036600319011261029d576004356000602060405161184b816128f5565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161188e836128f5565b818160a01c16835260c81c1660208201526118bf825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d576118fe613954565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611938913691612c28565b9182519161194583612c10565b926119536040519485612942565b808452601f1961196282612c10565b018660005b828110611b305750505064ffffffffff90814216936001600160801b03968761198f826139b0565b515116828a61199d846139b0565b51015116858060406119ae866139b0565b5101511689011690604051926119c3846128d9565b83528b83015260408201526119d7886139b0565b526119e1876139b0565b506001938760015b8a8c878310611aaf5790838b8b611a0281600401612d31565b92611a0f60248301612d31565b92611a1c60448401612d1d565b946064840135946001600160a01b039586811680910361029d57611aa798611a6798611a9c98611a4e60848a01612d45565b9481611a5c60a48c01612d45565b976040519d8e6128bc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612cc8565b6101008201526139d1565b604051908152f35b889385806040611ae38b86611ad38a8e9a611aca828d6139bd565b5151169a6139bd565b51015116946000198901906139bd565b51015116816040611af4888c6139bd565b5101511601169160405193611b08856128d9565b84528301526040820152611b1c828c6139bd565b52611b27818b6139bd565b500188906119e9565b611b38612d52565b828289010152018790611967565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b7890369060040161281a565b9160243590811161029d57611b9190369060040161281a565b9091611b9b613954565b818403611c0a5760005b848110611bae57005b80611c04611bbf6001938886612cf7565b35611bcb838987612cf7565b3560005260036020526001600160a01b0360406000205416611bf6611bf185898b612cf7565b612d1d565b91611bff613954565b61335b565b01611ba5565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161414f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cb98261378c565b60058110156109b557600203611cd7575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cca565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d38613954565b816000526009815260ff60016040600020015460a81c161561073b57816000526009815260ff60016040600020015460a01c1615611ec157611d79826140e6565b156115c35781600052600381526001600160a01b038060406000205416151580611eb9575b80611e9f575b611e87577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e4c575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e3457005b60249060405190637e27328960e01b82526004820152fd5b611e6d85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611de4565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615611da4565b506000611d9e565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f00366127e5565b60405191602083019383851067ffffffffffffffff8611176110515761029b9460405260008452612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611f9e613954565b81600052600980825260ff60016040600020015460a81c16156122235782600052808252604060002060ff600182015460a01c16600014611ff15760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61220b576120198360005260096020526001600160a01b0360406000205416331490565b156121ec5761202783613714565b8360005281835261203e6002604060002001612d71565b936001600160801b03918286511683821610156115e2578160005283855260ff60406000205460f01c16156115ab576120a6818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906129b8565b94826000528481526040600020956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895582169788156121d2575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5087604060002054169788938652600160406000200154169361215b8c8487614637565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b61218d57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121c957005b61029b90612911565b60018101600160a01b60ff60a01b198254161790556120ec565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d57612275613954565b60405191612282836128bc565b61228e826004016127d1565b835261229c602483016127d1565b60208401526122ad60448301612980565b604084015260648201356001600160a01b038116810361029d5760608401526122d8608483016128af565b60808401526122e960a483016128af565b60a08401526122fa60c48301612bfe565b60c084015260e482013590811161029d578101913660238401121561029d57611a9c611aa7926123366020953690602460048201359101612c28565b60e0840152610104369101612cc8565b3461029d5761029b612357366127e5565b916129d1565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576123b59061378c565b60058110156109b55780602091159081156123d6575b506040519015158152f35b6001915014826123cb565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c1680612474575b61244b575b50506001600160801b0360405191168152f35b61246d92506001600160801b0360026124679201541691613714565b906129b8565b8280612438565b5060ff600182015460a01c1615612433565b3461029d57604036600319011261029d5761249f6127a5565b6024356124ab816136f1565b33151580612574575b80612546575b6125165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff60406000205416156124ba565b50336001600160a01b03821614156124b4565b3461029d57602036600319011261029d576020611816600435612994565b3461029d57600036600319011261029d576040516000600190600154918260011c9160018416918215612661575b6020948585108414610bcd578587948686529182600014610bad5750506001146126045750610b3c92500383612942565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612649575050610b3c935082010185610b2f565b80548389018501528794508693909201918101612632565b92607f16926125d3565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612733575b8115612709575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612702565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126fb565b60005b8381106127705750506000910152565b8181015183820152602001612760565b906020916127998151809281855285808601910161275d565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b82811061286b575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161285d565b3590811515820361029d57565b610120810190811067ffffffffffffffff82111761105157604052565b6060810190811067ffffffffffffffff82111761105157604052565b6040810190811067ffffffffffffffff82111761105157604052565b67ffffffffffffffff811161105157604052565b610140810190811067ffffffffffffffff82111761105157604052565b90601f8019910116810190811067ffffffffffffffff82111761105157604052565b67ffffffffffffffff811161105157601f01601f191660200190565b35906001600160801b038216820361029d57565b61299d816136f1565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116116b657565b906001600160a01b0380911680156106f35760009184835260209160038352604092828486205416151580612bf6575b80612bde575b612bc7578685526003815282848620541694873315159384612b17575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612adf575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612ab15750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b0082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612a4d565b91929380915090612b86575b15612b315790878392612a24565b848887612b4e576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612bab575b80612b235750878252600583523384868420541614612b23565b5085825260068352848220338352835260ff8583205416612b91565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615612a07565b506001612a01565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110515760051b60200190565b929192612c3482612c10565b604094612c446040519283612942565b8195848352602080930191606080960285019481861161029d57925b858410612c705750505050505050565b868483031261029d57825190612c85826128d9565b612c8e85612980565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612cb9868801612bfe565b86820152815201930192612c60565b919082604091031261029d57604051612ce0816128f5565b6020808294612cee816127d1565b84520135910152565b9190811015612d075760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612d5f826128d9565b60006040838281528260208201520152565b90604051612d7e816128d9565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612db181612c10565b92604093612dc26040519182612942565b82815280946020809201926000526020600020906000935b858510612de957505050505050565b60018481928451612df9816128d9565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612dda565b9190612e428282856129d1565b803b612e4f575b50505050565b612eab6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612780565b03906020816000938185885af190829082612f41575b5050612ef85782612ed06141ca565b8051919082612ef15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f29575038808080612e49565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612fa1575b81612f5e60209383612942565b81010312612f9d5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612f9a5750903880612ec1565b80fd5b5080fd5b3d9150612f51565b92919092612fb5613954565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133455784885281865260ff6001858a20015460a01c1661332e576001600160a01b0391828216928315613317576001600160801b039384861691821561330057888c5260038a5280888d2054169384831415806132f0575b6132cd5761303b8a6141fa565b878116851161329c57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061306c91614222565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130a190612d71565b9080868301511691818481835116920151166130bc916129b8565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9661326f575b878252855220015416946130ff818988614637565b8a51908152a48033141580613265575b613200575b8233141590816131f5575b816131ea575b50613159575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156131e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16131d7575b85948161312b565b6131e090612911565b386131cf565b8780fd5b905082141538613125565b833b1515915061311f565b803b15613261578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af1613252575b50613114565b61325b90612911565b3861324c565b8880fd5b50803b151561310f565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556130ea565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506132fa8a6140e6565b1561302e565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613345578785815281875260ff6001868320015460a01c166136da576001600160a01b03908185169283156136c3576001600160801b03938486169182156136ac5789845260038b5284898520541694858314158061369c575b613679576134008b838e6133ec8361414f565b9289525260028c8820015460801c906129b8565b87811685116136485750908b8b928387528282528b808820998b838c54169b6002015460801c9061343091614222565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561346590612d71565b8180868301511693818351169201511661347e916129b8565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361361a575b848852825260018c8820015416946134c2818c88614637565b8b51908152a48133141580613610575b6135aa575b5081331415908161359f575b81613594575b5061351c575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613590578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613578575b808061312b565b6135828691612911565b61358c5784613571565b8480fd5b8280fd5b9050811415386134e9565b823b151591506134e3565b813b15612f9a578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16135fc575b506134d7565b61360891929a50612911565b9738806135f6565b50813b15156134d2565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134a9565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136a68b6140e6565b156133d9565b60248a8a519063d2aabcd960e01b82526004820152fd5b602488885190630ff7ee2d60e31b82526004820152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e34575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137825760c81c1611156137705750600a602052600160406000205411600014613767576137649061430e565b90565b6137649061423d565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137b3575050600490565b805460f81c61380c575460a01c64ffffffffff164210613806576137d681613714565b9060005260096020526001600160801b03806002604060002001541691161060001461380157600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613949575b80613931575b61391a579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138e2575b1692836138cc575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a8565b61390386600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138a0565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561383f565b508181161515613839565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398657565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d075760200190565b8051821015612d075760209160051b010190565b906139f36001600160801b0360408401511660206101008501510151906144ed565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140bc5780156140925781518015614068577f00000000000000000000000000000000000000000000000000000000000000008111614037575064ffffffffff6040613a5c846139b0565b51015116811015613fe05750600090819082815184905b808210613f4f575050505064ffffffffff421664ffffffffff8216811015613f0f5750506001600160801b0316808203613ed8575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c0f8951996000198b01906139bd565b51015160c81b169560f01b16911617171717845560005b818110613e06575050600185016007556001600160a01b0360208301511680156106f357613c5c866001600160a01b0392613813565b16613dd557613c876001600160a01b036060840151166001600160801b0383511690309033906145c6565b6001600160801b0360208201511680613da5575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613d9a613d7b60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d248c6128f5565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061284b565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613dcf906001600160a01b036060850151166001600160a01b0361010086015151169033906145c6565b38613c9b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e238160e08701516139bd565b518254680100000000000000008110156110515760018101808555811015612d0757600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c26565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613f73906001600160801b03613f6a85886139bd565b51511690614222565b9364ffffffffff806040613f8786856139bd565b51015116941680851115613fa357506001849301909291613a73565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613ff1846139b0565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b03806040842054169283331493841561412b575b5050821561411957505090565b9091506141263392612994565b161490565b60ff929450906040918152600660205281812033825260205220541691388061410c565b8060005260096020526141686002604060002001612d71565b816000526009602052604060002060ff600182015460a01c1660001461419b57506001600160801b039150602001511690565b5460f81c6141ad575061376490613714565b61376491506001600160801b0360408183511692015116906129b8565b3d156141f5573d906141db82612964565b916141e96040519384612942565b82523d6000602084013e565b606090565b613764906142078161414f565b90600052600960205260026040600020015460801c906129b8565b9190916001600160801b03808094169116019182116116b657565b64ffffffffff614272600091838352600960205280806040852054818160a01c1693849160c81c160316918142160316614691565b91808252600a602052604082208054156142fa5790829167ffffffffffffffff93526142cc602083205482845260096020526142c76001600160801b03968760026040882001541696879360801c1690614781565b6147ef565b9283136142e25750506142de906148d9565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161433483612925565b8054966101206143ba60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612d71565b94019384528452600a6020526143d1858520612da5565b91849680876143df866139b0565b5101511692828288955b16106144b757509161445d6142c79284888161446298976001600160801b039e8f614414898c6139bd565b5151169d8e9a67ffffffffffffffff602061442f8c846139bd565b5101511699848361444083856139bd565b5101511696508061449c57505050511680925b0316920316614691565b614781565b92831361447b57505061447583916148d9565b16011690565b5160200151929392831692841683101591506144979050575090565b905090565b6144ac92935060001901906139bd565b510151168092614453565b8093986001600160801b0390816144ce8c896139bd565b51511601169801928282808a6144e4888a6139bd565b510151166143e9565b919091604051906144fd826128f5565b600091828152826020820152936001600160801b03928383169182156145a75767016345785d8a000080821161457057506145398591846154a1565b166020870192818452111561455c57509082614557925116906129b8565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906145bb826128f5565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110515761463592604052614915565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146359161468c606483612942565b614915565b600160ff1b808214908115614777575b5061474d576000811215614744576146ca816000035b600084121561473d5783600003906149b1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470657600019911813156147005790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149b1565b6146ca816146b7565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146a1565b8061479c575061479757670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146147e95750806147c1575050670de0b6b3a764000090565b670de0b6b3a764000081146147e5576147e0906142c761376493614aab565b614bed565b5090565b91505090565b600160ff1b8082149081156148cf575b506148a557600081121561489c57614828816000035b60008412156148955783600003906154a1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485e57600019911813156147005790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154a1565b61482881614815565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386147ff565b600081126148e45790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614940600080836020829551910182875af16149396141ca565b9084615550565b908151918215159283614989575b5050506149585750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612f9d576020015190811591821503612f9a575038808061494e565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a6d5782851015614a3157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a7b570490565b634e487b7160e01b600052601260045260246000fd5b8015614a7b576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bbc57670de0b6b3a764000092838112614b9957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614b8d57506706f05b59d3b20000905b848213614b615750505050500290565b808391020590671bc16d674ec80000821215614b80575b831d90614b51565b8091950194831d90614b78565b93505093925050020290565b6000199392508015614a7b576ec097ce7bc90715b34b9f10000000000591614acc565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c1c5768033dd1780914b9711419811261380657614c1390600003614bed565b61376490614a91565b680a688906bd8affffff811361547057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615353575b66ff000000000000831661524b575b65ff0000000000831661514b575b64ff000000008316615053575b63ff0000008316614f63575b62ff00008316614e7b575b61ff008316614d9b575b60ff8316614cc4575b02911c60bf031c90565b60808316614d89575b838316614d77575b60208316614d65575b60108316614d53575b60088316614d41575b60048316614d2f575b60028316614d1d575b6001831615614cba576801000000000000000102831c614cba565b6801000000000000000102831c614d02565b6801000000000000000302831c614cf9565b6801000000000000000602831c614cf0565b6801000000000000000b02831c614ce7565b6801000000000000001602831c614cde565b6801000000000000002c02831c614cd5565b6801000000000000005902831c614ccd565b6180008316614e69575b6140008316614e57575b6120008316614e45575b6110008316614e33575b6108008316614e21575b6104008316614e0f575b6102008316614dfd575b610100831615614cb157680100000000000000b102831c614cb1565b6801000000000000016302831c614de1565b680100000000000002c602831c614dd7565b6801000000000000058c02831c614dcd565b68010000000000000b1702831c614dc3565b6801000000000000162e02831c614db9565b68010000000000002c5d02831c614daf565b680100000000000058b902831c614da5565b628000008316614f51575b624000008316614f3f575b622000008316614f2d575b621000008316614f1b575b620800008316614f09575b620400008316614ef7575b620200008316614ee5575b62010000831615614ca7576801000000000000b17202831c614ca7565b680100000000000162e402831c614ec8565b6801000000000002c5c802831c614ebd565b68010000000000058b9102831c614eb2565b680100000000000b172102831c614ea7565b68010000000000162e4302831c614e9c565b680100000000002c5c8602831c614e91565b6801000000000058b90c02831c614e86565b63800000008316615041575b6340000000831661502f575b6320000000831661501d575b6310000000831661500b575b63080000008316614ff9575b63040000008316614fe7575b63020000008316614fd5575b6301000000831615614c9c5768010000000000b1721802831c614c9c565b6801000000000162e43002831c614fb7565b68010000000002c5c86002831c614fab565b680100000000058b90c002831c614f9f565b6801000000000b17217f02831c614f93565b680100000000162e42ff02831c614f87565b6801000000002c5c85fe02831c614f7b565b68010000000058b90bfc02831c614f6f565b6480000000008316615139575b6440000000008316615127575b6420000000008316615115575b6410000000008316615103575b64080000000083166150f1575b64040000000083166150df575b64020000000083166150cd575b640100000000831615614c9057680100000000b17217f802831c614c90565b68010000000162e42ff102831c6150ae565b680100000002c5c85fe302831c6150a1565b6801000000058b90bfce02831c615094565b68010000000b17217fbb02831c615087565b6801000000162e42fff002831c61507a565b68010000002c5c8601cc02831c61506d565b680100000058b90c0b4902831c615060565b658000000000008316615239575b654000000000008316615227575b652000000000008316615215575b651000000000008316615203575b6508000000000083166151f1575b6504000000000083166151df575b6502000000000083166151cd575b65010000000000831615614c83576801000000b17218355102831c614c83565b680100000162e430e5a202831c6151ad565b6801000002c5c863b73f02831c61519f565b68010000058b90cf1e6e02831c615191565b680100000b1721bcfc9a02831c615183565b68010000162e43f4f83102831c615175565b680100002c5c89d5ec6d02831c615167565b6801000058b91b5bc9ae02831c615159565b66800000000000008316615341575b6640000000000000831661532f575b6620000000000000831661531d575b6610000000000000831661530b575b660800000000000083166152f9575b660400000000000083166152e7575b660200000000000083166152d5575b6601000000000000831615614c755768010000b17255775c0402831c614c75565b6801000162e525ee054702831c6152b4565b68010002c5cc37da949202831c6152a5565b680100058ba01fb9f96d02831c615296565b6801000b175effdc76ba02831c615287565b680100162f3904051fa102831c615278565b6801002c605e2e8cec5002831c615269565b68010058c86da1c09ea202831c61525a565b6780000000000000008316615451575b674000000000000000831661543f575b672000000000000000831661542d575b671000000000000000831661541b575b6708000000000000008316615409575b67040000000000000083166153f7575b67020000000000000083166153e5575b670100000000000000831615614c6657680100b1afa5abcbed6102831c614c66565b68010163da9fb33356d802831c6153c3565b680102c9a3e778060ee702831c6153b3565b6801059b0d31585743ae02831c6153a3565b68010b5586cf9890f62a02831c615393565b6801172b83c7d517adce02831c615383565b6801306fe0a31b7152df02831c615373565b5077b504f333f9de648480000000000000000000000000000000615363565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461553f57670de0b6b3a7640000908183101561550857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061558f575080511561556557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155da575b6155a0575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561559856fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f620049bc3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145df9081620003dd82396080518161396b0152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f8a57508063027b674414612f6757806306fdde0314612ea2578063081812fc14612e83578063095ea7b314612d8a5780631400ecec14612cea5780631c1cdd4c14612c855780631e99d56914612c6757806323b872dd14612c4f57806340e58ee5146129bc578063425d30dd1461296b57806342842e0e1461291b57806342966c6814612744578063442675701461271d5780634857501f146126a75780634869e12d1461266c5780634cc55e11146121c457806353b15727146120a55780636352211e146120755780636d0cee751461207557806370a082311461200557806375829def14611f72578063780a82c814611f255780637cad6cd114611e2b5780637de6b1db14611c045780638659c270146118b2578063894e9a0d146115925780638f69b993146114f65780639067b677146114a657806395d89b4114611397578063a22cb465146112da578063a80fc07114611288578063ab167ccc1461113e578063ad35efd4146110dc578063b25645691461108b578063b88d4fde14610ffe578063b8a3be6614610fc9578063b971302a14610f7a578063bc2be1be14610f2a578063c156a11d14610a65578063c87b56dd14610949578063cc364f481461087e578063d4dbd20b1461082c578063d511609f146107e0578063d975dfed14610794578063e985e9c51461073f578063ea5ead1914610717578063eac8f5b8146106c5578063f590c17614610663578063f851a4401461063d5763fdd46d601461025257600080fd5b3461063a57606036600319011261063a576004359061026f6130b9565b91610278613216565b92610281613961565b818352600960209181835260ff600160408720015460a81c16156106235783855281835260ff600160408720015460a01c1661060b576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614148565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b613509565b906103b181868401511692826040818351169201511690613250565b161115610532575b848c528252600160408c20015416946103d3818a88614170565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613135565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613135565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d5896139bd565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461063a578060031936011261063a576001600160a01b036020915416604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a57600435906107356130b9565b9161027881614148565b503461063a57604036600319011261063a576107596130a3565b60406107636130b9565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091614148565b6001600160801b0360405191168152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57604082600292602094526009845220015460801c604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760036040836001600160801b0393602095526009855220015416604051908152f35b503461063a576020908160031936011261063a576004359161089e6134ea565b508282526009815260ff600160408420015460a81c16156109325760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c1691604051936108f985613166565b8452830152604082015261093060405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a5557600435610968816136be565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a595780936109d8575b50506109d460405192828493845283019061307e565b0390f35b909192503d8082843e6109eb81846131d8565b8201918381840312610a555780519067ffffffffffffffff821161049c570182601f82011215610a5557805191610a21836131fa565b93610a2f60405195866131d8565b83855285848401011161063a575090610a4d9184808501910161305b565b9038806109be565b5080fd5b604051903d90823e3d90fd5b503461063a57604036600319011261063a57600435610a826130b9565b610a8a613961565b81835260099060209082825260ff600160408720015460a81c161561062357838552600382526001600160a01b03918260408720541693843303610f0b57610ad186614148565b906001600160801b039081831680158015610b71575b50505050505081811615610b595783610aff91613820565b90811680610b1f5760248460405190637e27328960e01b82526004820152fd5b8203610b29578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b79613961565b898b5282865260ff600160408d20015460a81c1615610ef457898b5282865260ff600160408d20015460a01c16610edc578815610ec457610eac57888a52600385528660408b205416918289141580610e9c575b610e7857610bda8a614148565b8481168311610e465750898b5280865260408b20938260028a87541696015460801c01818111610e325790610c418d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610c5d818a8401511692826040818351169201511690613250565b161115610e03575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610ca4818688614170565b604051908152a48033141580610df9575b610d8f575b813314159081610d84575b81610d79575b50610d08575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610ae7565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d61575b80610cd1565b610d6a90613135565b610d75578538610d5b565b8580fd5b905081141538610ccb565b823b15159150610cc5565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610de5575b5050610cba565b610dee90613135565b6104a0578338610dde565b50803b1515610cb5565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c65565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ea68a6139bd565b15610bcd565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae576040826001600160a01b03926020945260098452205416604051908152f35b503461063a57602036600319011261063a5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063a57608036600319011261063a576110186130a3565b6110206130b9565b906064359067ffffffffffffffff82116104a057366023830112156104a0578160040135928461104f856131fa565b9361105d60405195866131d8565b8585523660248783010111610a55578561108896602460209301838801378501015260443591613551565b80f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761111590613799565b60405190600581101561112a57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063a5761014036600319011261063a57611159613961565b6111616134ea565b9064ffffffffff8042168084528161117761353d565b16611272575b60e43590828216820361126d5701166040830152600435916001600160a01b039182841680940361126d576024359083821680920361126d57604435906001600160801b03821680920361126d576064359085821680920361063a57506084359182151580930361126d5760a4359384151580950361126d576040519761120389613149565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261126d576040519161123d836131bc565b61010435918216820361126d57826112659260209452610124358482015260e0820152613aa4565b604051908152f35b600080fd5b8161127b61353d565b820116602085015261117d565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760026040836001600160801b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a576112f46130a3565b6024359081151580920361126d576001600160a01b03169081156113665733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a578060031936011261063a5760405190806002549160018360011c926001851694851561149c575b60209586861081146114885785885287949392918790821561146657505060011461140c575b50506113f8925003836131d8565b6109d460405192828493845283019061307e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061144e5750506113f8935082010138806113ea565b80548389018501528794508693909201918101611436565b92509350506113f894915060ff191682840152151560051b82010138806113ea565b602483634e487b7160e01b81526022600452fd5b93607f16936113c4565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761152f90613799565b90600582101590816115705760028314918215611584575b821561155b575b6020836040519015158152f35b9091506115705750600460209114388061154e565b80634e487b7160e01b602492526021600452fd5b506003831491506000611547565b503461063a57602036600319011261063a57806101606040516115b481613182565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115f76134ea565b61014082015201526004358152600960205260ff600160408320015460a81c161561189a576004358152600960205260408120906116c560026040519361163d8561319f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613509565b6101208301526116d6600435613799565b6005811015611886576101606101c093600264ffffffffff931461187b575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6117828d613182565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b8360608201526116f5565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063a57602080600319360112610a555760043567ffffffffffffffff811161049c576118e5903690600401613104565b91906118ef613961565b83925b8084106118fd578480f35b6119088482846134c4565b3593611912613961565b848652600980855260ff600191818360408b20015460a81c1615611bed57878952808752604089208381015460a01c8316156119605760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611bd5576119918160005260096020526001600160a01b0360406000205416331490565b15611bb55761199f816136e1565b93818a528289526119b5600260408c2001613509565b946001600160801b0394858751168683161015611b9d57838c52848b5260408c205460f01c1615611b8557918493918a611a0185878f9a99808c9986928d511603169a01511690613250565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611ad160408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611b6c575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611aa98b8588614170565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611b15575b5050505050506001019291906118f2565b813b15610d7557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b58575b80808080611b04565b611b6190613135565b610524578438611b4f565b818601600160a01b60ff60a01b19825416179055611a68565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063a57602080600319360112610a555760043590611c23613961565b8183526009815260ff600160408520015460a81c1615611e1457611c4682613799565b6005811015611e005760048103611c6f5760248360405190634a5541ef60e01b82526004820152fd5b60038103611c8f576024836040519063fe19f19f60e01b82526004820152fd5b600214611de857611cb68260005260096020526001600160a01b0360406000205416331490565b15611dc9578183526009815260ff604084205460f01c1615611db157818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611d59575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611d9d575b80611d2a565b611da690613135565b61049c578238611d97565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a576004356001600160a01b039081811680910361049c5781835416338103611efc575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611ee85760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063a57602036600319011261063a57611f8c6130a3565b9080546001600160a01b0380821693338503611fde576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461063a57602036600319011261063a576001600160a01b036120276130a3565b168015612044578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57602036600319011261063a5760206120946004356136be565b6001600160a01b0360405191168152f35b503461063a5761016036600319011261063a576120c0613961565b604051906120cd82613149565b6120d56130a3565b82526120df6130b9565b60208301526120ec613216565b60408301526001600160a01b03906064358281168103610a55576060840152608435801515810361126d57608084015260a435801515810361126d5760a084015260603660c319011261063a575060405161214681613166565b64ffffffffff60c435818116810361126d57825260e435818116810361126d57602083015261010435908116810361126d57604082015260c083015260406101231936011261126d576040519161219c836131bc565b61012435918216820361126d57826112659260209452610144358482015260e0820152613aa4565b503461063a57604036600319011261063a5767ffffffffffffffff60043581811161049c576121f7903690600401613104565b90916024359081116104a057612211903690600401613104565b612219613961565b80830361263557845b83811061222d578580f35b6122388185876134c4565b35906122458186886134c4565b35875260036020526001600160a01b036040882054166122668285876134c4565b35906001600160801b038216820361126d57612280613961565b838952600960205260ff600160408b20015460a81c161561062357838952600960205260ff600160408b20015460a01c1661060b57801561261d576001600160801b038216156126055783895260036020526001600160a01b0360408a2054169182821415806125f5575b6125d1576122f885614148565b6001600160801b0381166001600160801b038316116125a15750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123898c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ad8160208401511692826040818351169201511690613250565b161115612570575b86855260096020526001600160a01b036001604087200154166123e26001600160801b0384168583614170565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612566575b6124fc575b8333141590816124f1575b816124e6575b50612474575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612222565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124ce575b808061243d565b6124d790613135565b6124e25786386124c7565b8680fd5b905083141538612437565b843b15159150612431565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612552575b5050612426565b61255b90613135565b61052457843861254b565b50803b1515612421565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b5565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125ff856139bd565b156122eb565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091613a26565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1457806126e283613799565b92600584101561188657600260209403612703575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126f7565b503461063a578060031936011261063a5760206001600160a01b0360085416604051908152f35b503461063a57602080600319360112610a555760043590612763613961565b8183526009815260ff600160408520015460a81c1615611e14578183526009815260ff600160408520015460a01c16156128ea576127a0826139bd565b15611dc95781600052600381526001600160a01b0380604060002054161515806128e2575b806128c8575b6128b0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612875575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161285d575080f35b60249060405190637e27328960e01b82526004820152fd5b61289685600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561280b565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c16156127cb565b5060006127c5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a5761292a366130cf565b60405191602083019383851067ffffffffffffffff8611176129555761108894604052858452613551565b634e487b7160e01b600052604160045260246000fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063a576020908160031936011261063a57600435906129dc613961565b818152600980845260ff600160408420015460a81c16156109325782825280845260408220600181015460a01c60ff1615612a295760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612c3757612a548260005260096020526001600160a01b0360406000205416331490565b15611dc957612a62826136e1565b93828452818152612a7860026040862001613509565b926001600160801b0391828551168388161015611de85781865283815260ff604087205460f01c1615611db1577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612ae1888584818b9c818c9d9c511603169a01511690613250565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612c1d575b01896001600160801b03198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612b898d8487614170565b8c612bb86040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612bcc578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c0e575b81818080808480f35b612c1790613135565b38612c05565b60018101600160a01b60ff60a01b19825416179055612b25565b6024826040519063fe19f19f60e01b82526004820152fd5b503461063a57611088612c61366130cf565b9161327f565b503461063a578060031936011261063a576020600754604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57612cbe90613799565b9060058210156115705760208215838115612cdf575b506040519015158152f35b600191501482612cd4565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611e1457602091604082828152600985522060ff815460f01c1680612d78575b612d4f575b50506001600160801b0360405191168152f35b612d7192506001600160801b036002612d6b92015416916136e1565b90613250565b3880612d3c565b5060ff600182015460a01c1615612d37565b503461063a57604036600319011261063a57612da46130a3565b602435612db0816136be565b33151580612e70575b80612e46575b612e165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612dbf565b50336001600160a01b0382161415612db9565b503461063a57602036600319011261063a57602061209460043561322c565b503461063a578060031936011261063a576040519080600191600154928360011c9260018516948515612f5d575b602095868610811461148857858852879493929187908215611466575050600114612f035750506113f8925003836131d8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f455750506113f8935082010138806113ea565b80548389018501528794508693909201918101612f2d565b93607f1693612ed0565b503461063a578060031936011261063a57602060405167016345785d8a00008152f35b905034610a55576020366003190112610a55576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613031575b8115613007575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613000565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612ff9565b60005b83811061306e5750506000910152565b818101518382015260200161305e565b906020916130978151809281855285808601910161305b565b601f01601f1916010190565b600435906001600160a01b038216820361126d57565b602435906001600160a01b038216820361126d57565b606090600319011261126d576001600160a01b0390600435828116810361126d5791602435908116810361126d579060443590565b9181601f8401121561126d5782359167ffffffffffffffff831161126d576020808501948460051b01011161126d57565b67ffffffffffffffff811161295557604052565b610100810190811067ffffffffffffffff82111761295557604052565b6060810190811067ffffffffffffffff82111761295557604052565b610180810190811067ffffffffffffffff82111761295557604052565b610140810190811067ffffffffffffffff82111761295557604052565b6040810190811067ffffffffffffffff82111761295557604052565b90601f8019910116810190811067ffffffffffffffff82111761295557604052565b67ffffffffffffffff811161295557601f01601f191660200190565b604435906001600160801b038216820361126d57565b613235816136be565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161326957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156134ac57600091848352602091600383526040928284862054161515806134a4575b8061348c575b6134755786855260038152828486205416948733151593846133c5575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761338d575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361335f5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133ae82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132fb565b91929380915090613434575b156133df57908783926132d2565b8488876133fc576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613459575b806133d157508782526005835233848684205416146133d1565b5085825260068352848220338352835260ff858320541661343f565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c16156132b5565b5060016132af565b6024604051633250574960e11b815260006004820152fd5b91908110156134d45760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134f782613166565b60006040838281528260208201520152565b9060405161351681613166565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361126d5790565b919061355e82828561327f565b803b61356b575b50505050565b6135c76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061307e565b03906020816000938185885af19082908261365d575b505061361457826135ec614118565b805191908261360d5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613645575038808080613565565b60249060405190633250574960e11b82526004820152fd5b909192506020813d6020116136b6575b8161367a602093836131d8565b81010312610a555751907fffffffff000000000000000000000000000000000000000000000000000000008216820361063a57509038806135dd565b3d915061366d565b8060005260036020526001600160a01b036040600020541690811561285d575090565b600090808252600a60205264ffffffffff918260408220541642106137935760096020526040812092835490808260c81c16918242101561377d576137329394955060a01c16809103904203614314565b9082815260096020526001600160801b03926137588460026040852001541680946143f4565b9283116137655750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c166000146137c0575050600490565b805460f81c613819575460a01c64ffffffffff164210613813576137e3816136e1565b9060005260096020526001600160801b03806002604060002001541691161060001461380e57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613956575b8061393e575b613927579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138ef575b1692836138d9575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138b5565b61391086600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138ad565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561384c565b508181161515613846565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361399357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415613a02575b505082156139f057505090565b9091506139fd339261322c565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139e3565b806000526009602052613a3f6002604060002001613509565b816000526009602052604060002060ff600182015460a01c16600014613a7257506001600160801b039150602001511690565b5460f81c613a875750613a84906136e1565b90565b613a8491506001600160801b036040818351169201511690613250565b90613ac56001600160801b03604084015116602060e08501510151906141cc565b916001600160801b0383511660c082015190156140ee5764ffffffffff815116156140c4576020810164ffffffffff81511680614014575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fd457505064ffffffffff8042169151169081811015613f94575050600754926001600160801b0381511660405190613b5482613166565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb68861319f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dae84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f76575b50600184016007556001600160a01b0360208301511680156134ac57613dfe856001600160a01b0392613820565b16613f4557613e296001600160a01b036060840151166001600160801b0383511690309033906142a5565b6001600160801b0360208201511680613f16575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0d6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3f906001600160a01b036060850151166001600160a01b0360e086015151169033906142a5565b38613e3d565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dd0565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561408457505064ffffffffff90511664ffffffffff60408301511690818110613afd576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614143573d90614129826131fa565b9161413760405193846131d8565b82523d6000602084013e565b606090565b613a849061415581613a26565b90600052600960205260026040600020015460801c90613250565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ca916141c56064836131d8565b6144a3565b565b919091604051906141dc826131bc565b600091828152826020820152936001600160801b03928383169182156142865767016345785d8a000080821161424f57506142188591846143f4565b166020870192818452111561423b5750908261423692511690613250565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061429a826131bc565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612955576141ca926040526144a3565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143d0578285101561439457908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143de570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461449257670de0b6b3a7640000908183101561445b57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144ce600080836020829551910182875af16144c7614118565b908461453f565b908151918215159283614517575b5050506144e65750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a5557602001519081159182150361063a57503880806144dc565b9061457e575080511561455457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145c9575b61458f575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561458756fea164736f6c6343000817000a"; + hex"60a034620003b757601f19906001600160401b0390601f620049bc3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145df9081620003dd82396080518161396b0152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f8a57508063027b674414612f6757806306fdde0314612ea2578063081812fc14612e83578063095ea7b314612d8a5780631400ecec14612cea5780631c1cdd4c14612c855780631e99d56914612c6757806323b872dd14612c4f57806340e58ee5146129bc578063425d30dd1461296b57806342842e0e1461291b57806342966c6814612744578063442675701461271d5780634857501f146126a75780634869e12d1461266c5780634cc55e11146121c457806353b15727146120a557806357404b1214611fda5780636352211e14611faa5780636d0cee7514611faa57806370a0823114611f3a57806375829def14611ea7578063780a82c814611e5a5780637cad6cd114611d605780637de6b1db14611b395780638659c270146117e7578063894e9a0d146114c75780638f69b9931461142b5780639067b677146113db57806395d89b41146112cc578063a22cb4651461120f578063a80fc071146111bd578063ab167ccc14611073578063ad35efd414611011578063b256456914610fc0578063b88d4fde14610f33578063b8a3be6614610efe578063b971302a14610eaf578063bc2be1be14610e5f578063c156a11d1461099a578063c87b56dd1461087e578063d4dbd20b1461082c578063d511609f146107e0578063d975dfed14610794578063e985e9c51461073f578063ea5ead1914610717578063eac8f5b8146106c5578063f590c17614610663578063f851a4401461063d5763fdd46d601461025257600080fd5b3461063a57606036600319011261063a576004359061026f6130b9565b91610278613216565b92610281613961565b818352600960209181835260ff600160408720015460a81c16156106235783855281835260ff600160408720015460a01c1661060b576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614148565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b613509565b906103b181868401511692826040818351169201511690613250565b161115610532575b848c528252600160408c20015416946103d3818a88614170565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613135565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613135565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d5896139bd565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461063a578060031936011261063a576001600160a01b036020915416604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a57600435906107356130b9565b9161027881614148565b503461063a57604036600319011261063a576107596130a3565b60406107636130b9565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091614148565b6001600160801b0360405191168152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57604082600292602094526009845220015460801c604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760036040836001600160801b0393602095526009855220015416604051908152f35b503461063a5760208060031936011261098a5760043561089d816136be565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa92831561098e57809361090d575b505061090960405192828493845283019061307e565b0390f35b909192503d8082843e61092081846131d8565b820191838184031261098a5780519067ffffffffffffffff821161049c570182601f8201121561098a57805191610956836131fa565b9361096460405195866131d8565b83855285848401011161063a5750906109829184808501910161305b565b9038806108f3565b5080fd5b604051903d90823e3d90fd5b503461063a57604036600319011261063a576004356109b76130b9565b6109bf613961565b81835260099060209082825260ff600160408720015460a81c161561062357838552600382526001600160a01b03918260408720541693843303610e4057610a0686614148565b906001600160801b039081831680158015610aa6575b50505050505081811615610a8e5783610a3491613820565b90811680610a545760248460405190637e27328960e01b82526004820152fd5b8203610a5e578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610aae613961565b898b5282865260ff600160408d20015460a81c1615610e2957898b5282865260ff600160408d20015460a01c16610e11578815610df957610de157888a52600385528660408b205416918289141580610dd1575b610dad57610b0f8a614148565b8481168311610d7b5750898b5280865260408b20938260028a87541696015460801c01818111610d675790610b768d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b92818a8401511692826040818351169201511690613250565b161115610d38575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610bd9818688614170565b604051908152a48033141580610d2e575b610cc4575b813314159081610cb9575b81610cae575b50610c3d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610a1c565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610c96575b80610c06565b610c9f90613135565b610caa578538610c90565b8580fd5b905081141538610c00565b823b15159150610bfa565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610d1a575b5050610bef565b610d2390613135565b6104a0578338610d13565b50803b1515610bea565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610b9a565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ddb8a6139bd565b15610b02565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae576040826001600160a01b03926020945260098452205416604051908152f35b503461063a57602036600319011261063a5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063a57608036600319011261063a57610f4d6130a3565b610f556130b9565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284610f84856131fa565b93610f9260405195866131d8565b858552366024878301011161098a5785610fbd96602460209301838801378501015260443591613551565b80f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761104a90613799565b60405190600581101561105f57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063a5761014036600319011261063a5761108e613961565b6110966134ea565b9064ffffffffff804216808452816110ac61353d565b166111a7575b60e4359082821682036111a25701166040830152600435916001600160a01b03918284168094036111a257602435908382168092036111a257604435906001600160801b0382168092036111a2576064359085821680920361063a5750608435918215158093036111a25760a435938415158095036111a2576040519761113889613149565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126111a25760405191611172836131bc565b6101043591821682036111a2578261119a9260209452610124358482015260e0820152613aa4565b604051908152f35b600080fd5b816111b061353d565b82011660208501526110b2565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760026040836001600160801b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a576112296130a3565b602435908115158092036111a2576001600160a01b031690811561129b5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a578060031936011261063a5760405190806002549160018360011c92600185169485156113d1575b60209586861081146113bd5785885287949392918790821561139b575050600114611341575b505061132d925003836131d8565b61090960405192828493845283019061307e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061138357505061132d9350820101388061131f565b8054838901850152879450869390920191810161136b565b925093505061132d94915060ff191682840152151560051b820101388061131f565b602483634e487b7160e01b81526022600452fd5b93607f16936112f9565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761146490613799565b90600582101590816114a557600283149182156114b9575b8215611490575b6020836040519015158152f35b9091506114a557506004602091143880611483565b80634e487b7160e01b602492526021600452fd5b50600383149150600061147c565b503461063a57602036600319011261063a57806101606040516114e981613182565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261152c6134ea565b61014082015201526004358152600960205260ff600160408320015460a81c16156117cf576004358152600960205260408120906115fa6002604051936115728561319f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613509565b61012083015261160b600435613799565b60058110156117bb576101606101c093600264ffffffffff93146117b0575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6116b78d613182565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b83606082015261162a565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063a5760208060031936011261098a5760043567ffffffffffffffff811161049c5761181a903690600401613104565b9190611824613961565b83925b808410611832578480f35b61183d8482846134c4565b3593611847613961565b848652600980855260ff600191818360408b20015460a81c1615611b2257878952808752604089208381015460a01c8316156118955760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611b0a576118c68160005260096020526001600160a01b0360406000205416331490565b15611aea576118d4816136e1565b93818a528289526118ea600260408c2001613509565b946001600160801b0394858751168683161015611ad257838c52848b5260408c205460f01c1615611aba57918493918a61193685878f9a99808c9986928d511603169a01511690613250565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a0660408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611aa1575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d20015416946119de8b8588614170565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a4a575b505050505050600101929190611827565b813b15610caa57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611a8d575b80808080611a39565b611a9690613135565b610524578438611a84565b818601600160a01b60ff60a01b1982541617905561199d565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063a5760208060031936011261098a5760043590611b58613961565b8183526009815260ff600160408520015460a81c1615611d4957611b7b82613799565b6005811015611d355760048103611ba45760248360405190634a5541ef60e01b82526004820152fd5b60038103611bc4576024836040519063fe19f19f60e01b82526004820152fd5b600214611d1d57611beb8260005260096020526001600160a01b0360406000205416331490565b15611cfe578183526009815260ff604084205460f01c1615611ce657818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611c8e575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611cd2575b80611c5f565b611cdb90613135565b61049c578238611ccc565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a576004356001600160a01b039081811680910361049c5781835416338103611e31575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611e1d5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063a57602036600319011261063a57611ec16130a3565b9080546001600160a01b0380821693338503611f13576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461063a57602036600319011261063a576001600160a01b03611f5c6130a3565b168015611f79578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57602036600319011261063a576020611fc96004356136be565b6001600160a01b0360405191168152f35b503461063a576020908160031936011261063a5760043591611ffa6134ea565b508282526009815260ff600160408420015460a81c161561208e5760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361205585613166565b8452830152604082015261208c60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063a5761016036600319011261063a576120c0613961565b604051906120cd82613149565b6120d56130a3565b82526120df6130b9565b60208301526120ec613216565b60408301526001600160a01b0390606435828116810361098a57606084015260843580151581036111a257608084015260a43580151581036111a25760a084015260603660c319011261063a575060405161214681613166565b64ffffffffff60c43581811681036111a257825260e43581811681036111a25760208301526101043590811681036111a257604082015260c08301526040610123193601126111a2576040519161219c836131bc565b6101243591821682036111a2578261119a9260209452610144358482015260e0820152613aa4565b503461063a57604036600319011261063a5767ffffffffffffffff60043581811161049c576121f7903690600401613104565b90916024359081116104a057612211903690600401613104565b612219613961565b80830361263557845b83811061222d578580f35b6122388185876134c4565b35906122458186886134c4565b35875260036020526001600160a01b036040882054166122668285876134c4565b35906001600160801b03821682036111a257612280613961565b838952600960205260ff600160408b20015460a81c161561062357838952600960205260ff600160408b20015460a01c1661060b57801561261d576001600160801b038216156126055783895260036020526001600160a01b0360408a2054169182821415806125f5575b6125d1576122f885614148565b6001600160801b0381166001600160801b038316116125a15750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123898c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ad8160208401511692826040818351169201511690613250565b161115612570575b86855260096020526001600160a01b036001604087200154166123e26001600160801b0384168583614170565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612566575b6124fc575b8333141590816124f1575b816124e6575b50612474575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612222565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124ce575b808061243d565b6124d790613135565b6124e25786386124c7565b8680fd5b905083141538612437565b843b15159150612431565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612552575b5050612426565b61255b90613135565b61052457843861254b565b50803b1515612421565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b5565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125ff856139bd565b156122eb565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091613a26565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611d4957806126e283613799565b9260058410156117bb57600260209403612703575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126f7565b503461063a578060031936011261063a5760206001600160a01b0360085416604051908152f35b503461063a5760208060031936011261098a5760043590612763613961565b8183526009815260ff600160408520015460a81c1615611d49578183526009815260ff600160408520015460a01c16156128ea576127a0826139bd565b15611cfe5781600052600381526001600160a01b0380604060002054161515806128e2575b806128c8575b6128b0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612875575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161285d575080f35b60249060405190637e27328960e01b82526004820152fd5b61289685600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561280b565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c16156127cb565b5060006127c5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a5761292a366130cf565b60405191602083019383851067ffffffffffffffff86111761295557610fbd94604052858452613551565b634e487b7160e01b600052604160045260246000fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063a576020908160031936011261063a57600435906129dc613961565b818152600980845260ff600160408420015460a81c161561208e5782825280845260408220600181015460a01c60ff1615612a295760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612c3757612a548260005260096020526001600160a01b0360406000205416331490565b15611cfe57612a62826136e1565b93828452818152612a7860026040862001613509565b926001600160801b0391828551168388161015611d1d5781865283815260ff604087205460f01c1615611ce6577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612ae1888584818b9c818c9d9c511603169a01511690613250565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612c1d575b01896001600160801b03198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612b898d8487614170565b8c612bb86040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612bcc578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c0e575b81818080808480f35b612c1790613135565b38612c05565b60018101600160a01b60ff60a01b19825416179055612b25565b6024826040519063fe19f19f60e01b82526004820152fd5b503461063a57610fbd612c61366130cf565b9161327f565b503461063a578060031936011261063a576020600754604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57612cbe90613799565b9060058210156114a55760208215838115612cdf575b506040519015158152f35b600191501482612cd4565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611d4957602091604082828152600985522060ff815460f01c1680612d78575b612d4f575b50506001600160801b0360405191168152f35b612d7192506001600160801b036002612d6b92015416916136e1565b90613250565b3880612d3c565b5060ff600182015460a01c1615612d37565b503461063a57604036600319011261063a57612da46130a3565b602435612db0816136be565b33151580612e70575b80612e46575b612e165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612dbf565b50336001600160a01b0382161415612db9565b503461063a57602036600319011261063a576020611fc960043561322c565b503461063a578060031936011261063a576040519080600191600154928360011c9260018516948515612f5d575b60209586861081146113bd5785885287949392918790821561139b575050600114612f0357505061132d925003836131d8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f4557505061132d9350820101388061131f565b80548389018501528794508693909201918101612f2d565b93607f1693612ed0565b503461063a578060031936011261063a57602060405167016345785d8a00008152f35b90503461098a57602036600319011261098a576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613031575b8115613007575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613000565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612ff9565b60005b83811061306e5750506000910152565b818101518382015260200161305e565b906020916130978151809281855285808601910161305b565b601f01601f1916010190565b600435906001600160a01b03821682036111a257565b602435906001600160a01b03821682036111a257565b60609060031901126111a2576001600160a01b039060043582811681036111a2579160243590811681036111a2579060443590565b9181601f840112156111a25782359167ffffffffffffffff83116111a2576020808501948460051b0101116111a257565b67ffffffffffffffff811161295557604052565b610100810190811067ffffffffffffffff82111761295557604052565b6060810190811067ffffffffffffffff82111761295557604052565b610180810190811067ffffffffffffffff82111761295557604052565b610140810190811067ffffffffffffffff82111761295557604052565b6040810190811067ffffffffffffffff82111761295557604052565b90601f8019910116810190811067ffffffffffffffff82111761295557604052565b67ffffffffffffffff811161295557601f01601f191660200190565b604435906001600160801b03821682036111a257565b613235816136be565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161326957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156134ac57600091848352602091600383526040928284862054161515806134a4575b8061348c575b6134755786855260038152828486205416948733151593846133c5575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761338d575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361335f5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133ae82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132fb565b91929380915090613434575b156133df57908783926132d2565b8488876133fc576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613459575b806133d157508782526005835233848684205416146133d1565b5085825260068352848220338352835260ff858320541661343f565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c16156132b5565b5060016132af565b6024604051633250574960e11b815260006004820152fd5b91908110156134d45760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134f782613166565b60006040838281528260208201520152565b9060405161351681613166565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036111a25790565b919061355e82828561327f565b803b61356b575b50505050565b6135c76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061307e565b03906020816000938185885af19082908261365d575b505061361457826135ec614118565b805191908261360d5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613645575038808080613565565b60249060405190633250574960e11b82526004820152fd5b909192506020813d6020116136b6575b8161367a602093836131d8565b8101031261098a5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361063a57509038806135dd565b3d915061366d565b8060005260036020526001600160a01b036040600020541690811561285d575090565b600090808252600a60205264ffffffffff918260408220541642106137935760096020526040812092835490808260c81c16918242101561377d576137329394955060a01c16809103904203614314565b9082815260096020526001600160801b03926137588460026040852001541680946143f4565b9283116137655750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c166000146137c0575050600490565b805460f81c613819575460a01c64ffffffffff164210613813576137e3816136e1565b9060005260096020526001600160801b03806002604060002001541691161060001461380e57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613956575b8061393e575b613927579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138ef575b1692836138d9575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138b5565b61391086600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138ad565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561384c565b508181161515613846565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361399357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415613a02575b505082156139f057505090565b9091506139fd339261322c565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139e3565b806000526009602052613a3f6002604060002001613509565b816000526009602052604060002060ff600182015460a01c16600014613a7257506001600160801b039150602001511690565b5460f81c613a875750613a84906136e1565b90565b613a8491506001600160801b036040818351169201511690613250565b90613ac56001600160801b03604084015116602060e08501510151906141cc565b916001600160801b0383511660c082015190156140ee5764ffffffffff815116156140c4576020810164ffffffffff81511680614014575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fd457505064ffffffffff8042169151169081811015613f94575050600754926001600160801b0381511660405190613b5482613166565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb68861319f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dae84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f76575b50600184016007556001600160a01b0360208301511680156134ac57613dfe856001600160a01b0392613820565b16613f4557613e296001600160a01b036060840151166001600160801b0383511690309033906142a5565b6001600160801b0360208201511680613f16575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0d6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3f906001600160a01b036060850151166001600160a01b0360e086015151169033906142a5565b38613e3d565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dd0565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561408457505064ffffffffff90511664ffffffffff60408301511690818110613afd576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614143573d90614129826131fa565b9161413760405193846131d8565b82523d6000602084013e565b606090565b613a849061415581613a26565b90600052600960205260026040600020015460801c90613250565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ca916141c56064836131d8565b6144a3565b565b919091604051906141dc826131bc565b600091828152826020820152936001600160801b03928383169182156142865767016345785d8a000080821161424f57506142188591846143f4565b166020870192818452111561423b5750908261423692511690613250565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061429a826131bc565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612955576141ca926040526144a3565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143d0578285101561439457908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143de570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461449257670de0b6b3a7640000908183101561445b57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144ce600080836020829551910182875af16144c7614118565b908461453f565b908151918215159283614517575b5050506144e65750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261098a57602001519081159182150361063a57503880806144dc565b9061457e575080511561455457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145c9575b61458f575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561458756fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004e3a3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a38908162000402823960805181613e1a015260a051818181612f2f0152613ec00152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461328d57508063027b67441461326a57806306fdde03146131a5578063081812fc14613186578063095ea7b31461308d5780631400ecec14612fed5780631c1cdd4c14612f885780631e99d56914612f6a57806323b872dd14612f525780632fe4304114612f1757806332fbe22b14612dbf57806340e58ee514612b0c578063425d30dd14612abb57806342842e0e14612a8157806342966c68146128aa57806344267570146128835780634857501f1461280d5780634869e12d146127d25780634cc55e111461230f5780636352211e146122df5780636d0cee75146122df57806370a082311461226f57806375829def146121dc5780637cad6cd1146120e25780637de6b1db14611ebb5780637f5799f914611e605780638659c27014611b05578063894e9a0d14611779578063897f362b146114c95780638f69b9931461142d5780639067b677146113dd57806395d89b41146112ce578063a22cb46514611211578063a80fc071146111bf578063ad35efd41461115d578063b25645691461110c578063b88d4fde1461107f578063b8a3be661461104a578063b971302a14610ffb578063bc2be1be14610fab578063c156a11d14610afc578063c87b56dd146109e0578063cc364f4814610948578063d4dbd20b146108f6578063d511609f146108aa578063d975dfed1461085e578063e985e9c514610809578063ea5ead191461070f578063eac8f5b8146106bd578063f590c1761461065b578063f851a440146106355763fdd46d601461025d57600080fd5b34610632576060366003190112610632576004359061027a6133bc565b91604435926001600160801b038085169182860361062d5761029a613e10565b83855260099560209387855260ff600160408920015460a81c16156106165785875287855260ff600160408920015460a01c166105fe576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961466b565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614693565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556103799061395f565b90808483015116918180825116916040015116610395916135a4565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886147f8565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b610498906134c5565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b610520906134c5565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614554565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106325780600319360112610632576001600160a01b036020915416604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576004359061072d6133bc565b916107378161466b565b92610740613e10565b81835260099360209185835260ff600160408720015460a81c16156107f25783855285835260ff600160408720015460a01c166107da576001600160a01b03918282169283156107c2576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961466b565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b5034610632576040366003190112610632576108236133a6565b604061082d6133bc565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a65761089960209161466b565b6001600160801b0360405191168152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082600292602094526009845220015460801c604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760036040836001600160801b0393602095526009855220015416604051908152f35b5034610632576020366003190112610632576004356000602060405161096d81613512565b8281520152808252600960205260ff600160408420015460a81c16156106a657604082819281526009602052205464ffffffffff8251916109ad83613512565b818160a01c16835260c81c1660208201526109de825180926020908164ffffffffff91828151168552015116910152565bf35b503461063257602080600319360112610aec576004356109ff81613b21565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610af0578093610a6f575b5050610a6b604051928284938452830190613381565b0390f35b909192503d8082843e610a82818461352e565b8201918381840312610aec5780519067ffffffffffffffff82116104a3570182601f82011215610aec57805191610ab883613550565b93610ac6604051958661352e565b838552858484010111610632575090610ae49184808501910161335e565b903880610a55565b5080fd5b604051903d90823e3d90fd5b503461063257604036600319011261063257600435610b196133bc565b610b21613e10565b81835260099060209082825260ff600160408720015460a81c16156107f257838552600382526001600160a01b03918260408720541693843303610f8c57610b688661466b565b906001600160801b039081831680158015610c08575b50505050505081811615610bf05783610b9691613ccf565b90811680610bb65760248460405190637e27328960e01b82526004820152fd5b8203610bc0578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610c10613e10565b898b5282865260ff600160408d20015460a81c1615610f7557898b5282865260ff600160408d20015460a01c16610f5d578815610f4557610f2d57888a52600385528660408b205416918289141580610f1d575b610ef957610c718a61466b565b8481168311610ec75750908a949392918a86528087526040862093610cd6610ca48760028d89541698015460801c614693565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b16911617815561395f565b90610cf2818a84015116928260408183511692015116906135a4565b161115610e98575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610d398186886147f8565b604051908152a48033141580610e8e575b610e24575b813314159081610e19575b81610e0e575b50610d9d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610b7e565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610df6575b80610d66565b610dff906134c5565b610e0a578538610df0565b8580fd5b905081141538610d60565b823b15159150610d5a565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610e7a575b5050610d4f565b610e83906134c5565b6104a7578338610e73565b50803b1515610d4a565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610cfa565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610f278a614554565b15610c64565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576040826001600160a01b03926020945260098452205416604051908152f35b50346106325760203660031901126106325760ff6001604060209360043581526009855220015460a81c166040519015158152f35b5034610632576080366003190112610632576110996133a6565b6110a16133bc565b906064359067ffffffffffffffff82116104a757366023830112156104a757816004013592846110d085613550565b936110de604051958661352e565b8585523660248783010111610aec5785611109966024602093018388013785010152604435916139b4565b80f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761119690613c48565b6040519060058110156111ab57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760026040836001600160801b0393602095526009855220015416604051908152f35b50346106325760403660031901126106325761122b6133a6565b6024359081151580920361062d576001600160a01b031690811561129d5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257806003193601126106325760405190806002549160018360011c92600185169485156113d3575b60209586861081146113bf5785885287949392918790821561139d575050600114611343575b505061132f9250038361352e565b610a6b604051928284938452830190613381565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061138557505061132f93508201013880611321565b8054838901850152879450869390920191810161136d565b925093505061132f94915060ff191682840152151560051b8201013880611321565b602483634e487b7160e01b81526022600452fd5b93607f16936112fb565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65761146690613c48565b90600582101590816114a757600283149182156114bb575b8215611492575b6020836040519015158152f35b9091506114a757506004602091143880611485565b80634e487b7160e01b602492526021600452fd5b50600383149150600061147e565b5034610632576020906003198281360112610aec576004359167ffffffffffffffff91828411610aec5761012084360391820112610aec57611509613e10565b60c48401359060221901811215610aec5783016004810135928311610aec5760248101908360061b80360383136104a7576024906115468661382a565b95611554604051978861352e565b8652878601920101913683116104a757905b86838310611761575050505081519061157e8261382a565b9261158c604051948561352e565b828452601f1961159b8461382a565b0186835b82811061173d5750505064ffffffffff804216936001600160801b0392836115c682613b44565b51511683808b6115d585613b44565b51015116880116604051916115e983613512565b82528a8201526115f888613b44565b5261160287613b44565b5060019260015b8381106116d457505050505061162185600401613993565b9161162e60248701613993565b9161163b604488016138cd565b6064880135926001600160a01b039081851680950361063257509288959261168c9895926116c1989561167360846116cc9d016139a7565b948161168160a48c016139a7565b976040519d8e6134a8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613878565b610100820152613e6c565b604051908152f35b8089838d8180826116f98d6116ea8e9a8d613b51565b51511696600019890190613b51565b5101511691611708868a613b51565b5101511601166040519161171b83613512565b82528d82015261172b828c613b51565b52611736818b613b51565b5001611609565b60405161174981613512565b6000815260008382015282828901015201879061159f565b60409161176e3685613842565b815201910190611566565b503461063257602036600319011261063257606061016060405161179c816134d9565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e082015283610100820152836101208201526040516117e2816134f6565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611aed5760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611ad7576118d39160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161395f565b6101208301526118e4600435613c48565b6005811015611ac3576101609261198f9260026119cb9314611ab8575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e6134d9565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138e1565b82820152610a6b604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061344c565b806060830152611901565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063257602080600319360112610aec5760043567ffffffffffffffff81116104a357611b3890369060040161341b565b9190611b42613e10565b83925b808410611b50578480f35b611b5b8482846138a7565b3593611b65613e10565b848652600980855260ff600191818360408b20015460a81c1615611e4957878952808752604089208381015460a01c831615611bb35760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611e3157611be48160005260096020526001600160a01b0360406000205416331490565b15611e1157611bf281613b65565b93818a52828952611c08600260408c200161395f565b946001600160801b0394858751168683161015611df957838c52848b5260408c205460f01c1615611de157918493918a611c5485878f9a99808c9986928d511603169a015116906135a4565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d2d60408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611dc8575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611d058b85886147f8565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611d71575b505050505050600101929190611b45565b813b15610e0a57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611db4575b80808080611d60565b611dbd906134c5565b61052b578438611dab565b818601600160a01b60ff60a01b19825416179055611cbb565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082611ea792610a6b9452600a602052206138e1565b60405191829160208352602083019061344c565b503461063257602080600319360112610aec5760043590611eda613e10565b8183526009815260ff600160408520015460a81c16156120cb57611efd82613c48565b60058110156120b75760048103611f265760248360405190634a5541ef60e01b82526004820152fd5b60038103611f46576024836040519063fe19f19f60e01b82526004820152fd5b60021461209f57611f6d8260005260096020526001600160a01b0360406000205416331490565b15612080578183526009815260ff604084205460f01c161561206857818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b612010575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1612054575b80611fe1565b61205d906134c5565b6104a357823861204e565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610632576020366003190112610632576004356001600160a01b03908181168091036104a357818354163381036121b3575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a2600754600019810190811161219f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b5034610632576020366003190112610632576121f66133a6565b9080546001600160a01b0380821693338503612248576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610632576020366003190112610632576001600160a01b036122916133a6565b1680156122ae578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106325760203660031901126106325760206122fe600435613b21565b6001600160a01b0360405191168152f35b50346106325760403660031901126106325767ffffffffffffffff6004358181116104a35761234290369060040161341b565b9091602490813590811161052b5761235e90369060040161341b565b612369929192613e10565b80840361279c57855b84811061237d578680f35b6123888186886138a7565b35906123958187896138a7565b35885260036020526001600160a01b036040892054166123be6123b98386896138a7565b6138cd565b906123c7613e10565b838a52600960205260ff600160408c20015460a81c161561278657838a52600960205260ff600160408c20015460a01c1661276f578015612758576001600160801b0382161561274157838a5260036020526001600160a01b0360408b205416918282141580612731575b61270d5761243f8561466b565b6001600160801b0381166001600160801b038316116126dd5750908a9291858452600960205260408420926124c56001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff196124a787608094851c614693565b938c8b52600960205260408b2001938454931b16911617815561395f565b6001600160801b036124e981602084015116928260408183511692015116906135a4565b1611156126ac575b86855260096020526001600160a01b0360016040872001541661251e6001600160801b03841685836147f8565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126a2575b612638575b83331415908161262d575b81612622575b506125b0575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612372565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161260a575b8080612579565b612613906134c5565b61261e578738612603565b8780fd5b905083141538612573565b843b1515915061256d565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161268e575b5050612562565b612697906134c5565b61052b578438612687565b50803b151561255d565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124f1565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061273b85614554565b15612432565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a6576108996020916145bd565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120cb578061284883613c48565b926005841015611ac357600260209403612869575b50506040519015158152f35b815260098352604090205460f01c60ff169050388061285d565b503461063257806003193601126106325760206001600160a01b0360085416604051908152f35b503461063257602080600319360112610aec57600435906128c9613e10565b8183526009815260ff600160408520015460a81c16156120cb578183526009815260ff600160408520015460a01c1615612a505761290682614554565b156120805781600052600381526001600160a01b038060406000205416151580612a48575b80612a2e575b612a16577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260038352604060002054169182159283156129db575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129c3575080f35b60249060405190637e27328960e01b82526004820152fd5b6129fc85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612971565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615612931565b50600061292b565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257612a90366133e6565b60405191602083019383851067ffffffffffffffff861117611ad757611109946040528584526139b4565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063257602090816003193601126106325760043590612b2c613e10565b818152600980845260ff600160408420015460a81c1615612da85782825280845260408220600181015460a01c60ff1615612b795760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612d9057612ba48260005260096020526001600160a01b0360406000205416331490565b1561208057612bb282613b65565b93828452818152612bc86002604086200161395f565b926001600160801b039182855116838816101561209f5781865283815260ff604087205460f01c1615612068577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612c31888584818b9c818c9d9c511603169a015116906135a4565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612d76575b01896fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612ce28d84876147f8565b8c612d116040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612d25578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d67575b81818080808480f35b612d70906134c5565b38612d5e565b60018101600160a01b60ff60a01b19825416179055612c75565b6024826040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b5034610632576003199060203683018113610aec576004359167ffffffffffffffff93848411610aec5761014090843603011261063257612dfe613e10565b60405193612e0b856134a8565b612e17846004016133d2565b8552612e25602485016133d2565b6020860152612e366044850161356c565b604086015260648401356001600160a01b03811681036104a3576060860152612e616084850161349b565b6080860152612e7260a4850161349b565b60a0860152612e8360c48501613818565b60c086015260e4840135908111610aec5783019136602384011215610aec576004830135612eb08161382a565b93612ebe604051958661352e565b8185526024602086019260061b820101933685116106325750602401905b838210612efe5760206116cc886116c1898960e0840152610104369101613878565b82604091612f0c3685613842565b815201910190612edc565b503461063257806003193601126106325760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461063257611109612f64366133e6565b916135d3565b50346106325780600319360112610632576020600754604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657612fc190613c48565b9060058210156114a75760208215838115612fe2575b506040519015158152f35b600191501482612fd7565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c16156120cb57602091604082828152600985522060ff815460f01c168061307b575b613052575b50506001600160801b0360405191168152f35b61307492506001600160801b03600261306e9201541691613b65565b906135a4565b388061303f565b5060ff600182015460a01c161561303a565b5034610632576040366003190112610632576130a76133a6565b6024356130b381613b21565b33151580613173575b80613149575b6131195781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff604085205416156130c2565b50336001600160a01b03821614156130bc565b50346106325760203660031901126106325760206122fe600435613580565b50346106325780600319360112610632576040519080600191600154928360011c9260018516948515613260575b60209586861081146113bf5785885287949392918790821561139d57505060011461320657505061132f9250038361352e565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061324857505061132f93508201013880611321565b80548389018501528794508693909201918101613230565b93607f16936131d3565b5034610632578060031936011261063257602060405167016345785d8a00008152f35b905034610aec576020366003190112610aec576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613334575b811561330a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613303565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506132fc565b60005b8381106133715750506000910152565b8181015183820152602001613361565b9060209161339a8151809281855285808601910161335e565b601f01601f1916010190565b600435906001600160a01b038216820361062d57565b602435906001600160a01b038216820361062d57565b35906001600160a01b038216820361062d57565b606090600319011261062d576001600160a01b0390600435828116810361062d5791602435908116810361062d579060443590565b9181601f8401121561062d5782359167ffffffffffffffff831161062d576020808501948460051b01011161062d57565b90815180825260208080930193019160005b82811061346c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161345e565b3590811515820361062d57565b610120810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757604052565b610180810190811067ffffffffffffffff821117611ad757604052565b6060810190811067ffffffffffffffff821117611ad757604052565b6040810190811067ffffffffffffffff821117611ad757604052565b90601f8019910116810190811067ffffffffffffffff821117611ad757604052565b67ffffffffffffffff8111611ad757601f01601f191660200190565b35906001600160801b038216820361062d57565b61358981613b21565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116135bd57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561380057600091848352602091600383526040928284862054161515806137f8575b806137e0575b6137c9578685526003815282848620541694873315159384613719575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876136e1575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136b35750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61370282600052600560205260406000206001600160a01b03198154169055565b87835260048452868320805460001901905561364f565b91929380915090613788575b156137335790878392613626565b848887613750576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156137ad575b806137255750878252600583523384868420541614613725565b5085825260068352848220338352835260ff8583205416613793565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615613609565b506001613603565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361062d57565b67ffffffffffffffff8111611ad75760051b60200190565b919082604091031261062d5760405161385a81613512565b602061387381839561386b8161356c565b855201613818565b910152565b919082604091031261062d5760405161389081613512565b602080829461389e816133d2565b84520135910152565b91908110156138b75760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361062d5790565b9081546138ed8161382a565b926040936138fe604051918261352e565b82815280946020809201926000526020600020906000935b85851061392557505050505050565b6001848192845161393581613512565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613916565b9060405161396c816134f6565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062d5790565b35801515810361062d5790565b91906139c18282856135d3565b803b6139ce575b50505050565b613a2a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613381565b03906020816000938185885af190829082613ac0575b5050613a775782613a4f61463b565b8051919082613a705760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aa85750388080806139c8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613b19575b81613add6020938361352e565b81010312610aec5751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106325750903880613a40565b3d9150613ad0565b8060005260036020526001600160a01b03604060002054169081156129c3575090565b8051156138b75760200190565b80518210156138b75760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b8860406000206138e1565b9084846020613b9685613b44565b5101511611613c3e57600052600960205260406000208484825460c81c161115613c2957506001600160801b039081613bce82613b44565b515116946001948594855b613be8575b5050505050505090565b8351871015613c2457828282613bfe8a88613b51565b5101511611613c24578585889981613c17849b89613b51565b5151160116980196613bd9565b613bde565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613c6f575050600490565b805460f81c613cc8575460a01c64ffffffffff164210613cc257613c9281613b65565b9060005260096020526001600160801b038060026040600020015416911610600014613cbd57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613e05575b80613ded575b613dd6579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d9e575b169283613d88575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d64565b613dbf86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d5c565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613cfb565b508181161515613cf5565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e4257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e8e6001600160801b0360408401511660206101008501510151906146ae565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452a57801561450057815180156144d6577f000000000000000000000000000000000000000000000000000000000000000081116144a5575064ffffffffff6020613ef784613b44565b5101511681101561444e5750600090819082815184905b8082106143bd575050505064ffffffffff421664ffffffffff821681101561437d5750506001600160801b0316808203614346575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140aa8951996000198b0190613b51565b51015160c81b169560f01b16911617171717845560005b8181106142a1575050600185016007556001600160a01b036020830151168015613800576140f7866001600160a01b0392613ccf565b16614270576141226001600160a01b036060840151166001600160801b038351169030903390614787565b6001600160801b0360208201511680614240575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661423561421660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141bf8c613512565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061344c565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61426a906001600160a01b036060850151166001600160a01b036101008601515116903390614787565b38614136565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142be8160e0870151613b51565b51825468010000000000000000811015611ad757600181018085558110156138b757600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140c1565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143e1906001600160801b036143d88588613b51565b51511690614693565b9364ffffffffff8060206143f58685613b51565b5101511694168085111561441157506001849301909291613f0e565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061445f84613b44565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614599575b5050821561458757505090565b9091506145943392613580565b161490565b60ff929450906040918152600660205281812033825260205220541691388061457a565b8060005260096020526145d6600260406000200161395f565b816000526009602052604060002060ff600182015460a01c1660001461460957506001600160801b039150602001511690565b5460f81c61461e575061461b90613b65565b90565b61461b91506001600160801b0360408183511692015116906135a4565b3d15614666573d9061464c82613550565b9161465a604051938461352e565b82523d6000602084013e565b606090565b61461b90614678816145bd565b90600052600960205260026040600020015460801c906135a4565b9190916001600160801b03808094169116019182116135bd57565b919091604051906146be82613512565b600091828152826020820152936001600160801b03928383169182156147685767016345785d8a000080821161473157506146fa8591846148e9565b166020870192818452111561471d57509082614718925116906135a4565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061477c82613512565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611ad7576147f69260405261484d565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147f69161484d60648361352e565b6001600160a01b031690614878600080836020829551910182875af161487161463b565b9084614998565b9081519182151592836148c1575b5050506148905750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610aec5760200151908115918215036106325750388080614886565b9091906000198382098382029182808310920391808303921461498757670de0b6b3a7640000908183101561495057947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149d757508051156149ad57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614a22575b6149e8575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149e056fea164736f6c6343000817000a"; + hex"60c034620003dc576001600160401b0390601f601f1962004e3a3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a38908162000402823960805181613e1a015260a051818181612f2f0152613ec00152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461328d57508063027b67441461326a57806306fdde03146131a5578063081812fc14613186578063095ea7b31461308d5780631400ecec14612fed5780631c1cdd4c14612f885780631e99d56914612f6a57806323b872dd14612f525780632fe4304114612f1757806332fbe22b14612dbf57806340e58ee514612b0c578063425d30dd14612abb57806342842e0e14612a8157806342966c68146128aa57806344267570146128835780634857501f1461280d5780634869e12d146127d25780634cc55e111461230f57806357404b12146122775780636352211e146122475780636d0cee751461224757806370a08231146121d757806375829def146121445780637cad6cd11461204a5780637de6b1db14611e235780637f5799f914611dc85780638659c27014611a6d578063894e9a0d146116e1578063897f362b146114315780638f69b993146113955780639067b6771461134557806395d89b4114611236578063a22cb46514611179578063a80fc07114611127578063ad35efd4146110c5578063b256456914611074578063b88d4fde14610fe7578063b8a3be6614610fb2578063b971302a14610f63578063bc2be1be14610f13578063c156a11d14610a64578063c87b56dd14610948578063d4dbd20b146108f6578063d511609f146108aa578063d975dfed1461085e578063e985e9c514610809578063ea5ead191461070f578063eac8f5b8146106bd578063f590c1761461065b578063f851a440146106355763fdd46d601461025d57600080fd5b34610632576060366003190112610632576004359061027a6133bc565b91604435926001600160801b038085169182860361062d5761029a613e10565b83855260099560209387855260ff600160408920015460a81c16156106165785875287855260ff600160408920015460a01c166105fe576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961466b565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614693565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556103799061395f565b90808483015116918180825116916040015116610395916135a4565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886147f8565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b610498906134c5565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b610520906134c5565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614554565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106325780600319360112610632576001600160a01b036020915416604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576004359061072d6133bc565b916107378161466b565b92610740613e10565b81835260099360209185835260ff600160408720015460a81c16156107f25783855285835260ff600160408720015460a01c166107da576001600160a01b03918282169283156107c2576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961466b565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b5034610632576040366003190112610632576108236133a6565b604061082d6133bc565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a65761089960209161466b565b6001600160801b0360405191168152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082600292602094526009845220015460801c604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760036040836001600160801b0393602095526009855220015416604051908152f35b503461063257602080600319360112610a545760043561096781613b21565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a585780936109d7575b50506109d3604051928284938452830190613381565b0390f35b909192503d8082843e6109ea818461352e565b8201918381840312610a545780519067ffffffffffffffff82116104a3570182601f82011215610a5457805191610a2083613550565b93610a2e604051958661352e565b838552858484010111610632575090610a4c9184808501910161335e565b9038806109bd565b5080fd5b604051903d90823e3d90fd5b503461063257604036600319011261063257600435610a816133bc565b610a89613e10565b81835260099060209082825260ff600160408720015460a81c16156107f257838552600382526001600160a01b03918260408720541693843303610ef457610ad08661466b565b906001600160801b039081831680158015610b70575b50505050505081811615610b585783610afe91613ccf565b90811680610b1e5760248460405190637e27328960e01b82526004820152fd5b8203610b28578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b78613e10565b898b5282865260ff600160408d20015460a81c1615610edd57898b5282865260ff600160408d20015460a01c16610ec5578815610ead57610e9557888a52600385528660408b205416918289141580610e85575b610e6157610bd98a61466b565b8481168311610e2f5750908a949392918a86528087526040862093610c3e610c0c8760028d89541698015460801c614693565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b16911617815561395f565b90610c5a818a84015116928260408183511692015116906135a4565b161115610e00575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610ca18186886147f8565b604051908152a48033141580610df6575b610d8c575b813314159081610d81575b81610d76575b50610d05575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610ae6565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d5e575b80610cce565b610d67906134c5565b610d72578538610d58565b8580fd5b905081141538610cc8565b823b15159150610cc2565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610de2575b5050610cb7565b610deb906134c5565b6104a7578338610ddb565b50803b1515610cb2565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c62565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610e8f8a614554565b15610bcc565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576040826001600160a01b03926020945260098452205416604051908152f35b50346106325760203660031901126106325760ff6001604060209360043581526009855220015460a81c166040519015158152f35b5034610632576080366003190112610632576110016133a6565b6110096133bc565b906064359067ffffffffffffffff82116104a757366023830112156104a7578160040135928461103885613550565b93611046604051958661352e565b8585523660248783010111610a545785611071966024602093018388013785010152604435916139b4565b80f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576110fe90613c48565b60405190600581101561111357602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760026040836001600160801b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576111936133a6565b6024359081151580920361062d576001600160a01b03169081156112055733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257806003193601126106325760405190806002549160018360011c926001851694851561133b575b6020958686108114611327578588528794939291879082156113055750506001146112ab575b50506112979250038361352e565b6109d3604051928284938452830190613381565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106112ed57505061129793508201013880611289565b805483890185015287945086939092019181016112d5565b925093505061129794915060ff191682840152151560051b8201013880611289565b602483634e487b7160e01b81526022600452fd5b93607f1693611263565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576113ce90613c48565b906005821015908161140f5760028314918215611423575b82156113fa575b6020836040519015158152f35b90915061140f575060046020911438806113ed565b80634e487b7160e01b602492526021600452fd5b5060038314915060006113e6565b5034610632576020906003198281360112610a54576004359167ffffffffffffffff91828411610a545761012084360391820112610a5457611471613e10565b60c48401359060221901811215610a545783016004810135928311610a545760248101908360061b80360383136104a7576024906114ae8661382a565b956114bc604051978861352e565b8652878601920101913683116104a757905b868383106116c957505050508151906114e68261382a565b926114f4604051948561352e565b828452601f196115038461382a565b0186835b8281106116a55750505064ffffffffff804216936001600160801b03928361152e82613b44565b51511683808b61153d85613b44565b5101511688011660405191611551836134d9565b82528a82015261156088613b44565b5261156a87613b44565b5060019260015b83811061163c57505050505061158985600401613993565b9161159660248701613993565b916115a3604488016138cd565b6064880135926001600160a01b03908185168095036106325750928895926115f498959261162998956115db60846116349d016139a7565b94816115e960a48c016139a7565b976040519d8e6134a8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613878565b610100820152613e6c565b604051908152f35b8089838d8180826116618d6116528e9a8d613b51565b51511696600019890190613b51565b5101511691611670868a613b51565b51015116011660405191611683836134d9565b82528d820152611693828c613b51565b5261169e818b613b51565b5001611571565b6040516116b1816134d9565b60008152600083820152828289010152018790611507565b6040916116d63685613842565b8152019101906114ce565b5034610632576020366003190112610632576060610160604051611704816134f5565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201528361012082015260405161174a81613512565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611a555760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a3f5761183b9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161395f565b61012083015261184c600435613c48565b6005811015611a2b57610160926118f79260026119339314611a20575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e6134f5565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138e1565b828201526109d3604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061344c565b806060830152611869565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063257602080600319360112610a545760043567ffffffffffffffff81116104a357611aa090369060040161341b565b9190611aaa613e10565b83925b808410611ab8578480f35b611ac38482846138a7565b3593611acd613e10565b848652600980855260ff600191818360408b20015460a81c1615611db157878952808752604089208381015460a01c831615611b1b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d9957611b4c8160005260096020526001600160a01b0360406000205416331490565b15611d7957611b5a81613b65565b93818a52828952611b70600260408c200161395f565b946001600160801b0394858751168683161015611d6157838c52848b5260408c205460f01c1615611d4957918493918a611bbc85878f9a99808c9986928d511603169a015116906135a4565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611c9560408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611d30575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611c6d8b85886147f8565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611cd9575b505050505050600101929190611aad565b813b15610d7257856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d1c575b80808080611cc8565b611d25906134c5565b61052b578438611d13565b818601600160a01b60ff60a01b19825416179055611c23565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082611e0f926109d39452600a602052206138e1565b60405191829160208352602083019061344c565b503461063257602080600319360112610a545760043590611e42613e10565b8183526009815260ff600160408520015460a81c161561203357611e6582613c48565b600581101561201f5760048103611e8e5760248360405190634a5541ef60e01b82526004820152fd5b60038103611eae576024836040519063fe19f19f60e01b82526004820152fd5b60021461200757611ed58260005260096020526001600160a01b0360406000205416331490565b15611fe8578183526009815260ff604084205460f01c1615611fd057818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611f78575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611fbc575b80611f49565b611fc5906134c5565b6104a3578238611fb6565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610632576020366003190112610632576004356001600160a01b03908181168091036104a3578183541633810361211b575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121075760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106325760203660031901126106325761215e6133a6565b9080546001600160a01b03808216933385036121b0576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610632576020366003190112610632576001600160a01b036121f96133a6565b168015612216578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610632576020366003190112610632576020612266600435613b21565b6001600160a01b0360405191168152f35b5034610632576020366003190112610632576004356000602060405161229c816134d9565b8281520152808252600960205260ff600160408420015460a81c16156106a657604082819281526009602052205464ffffffffff8251916122dc836134d9565b818160a01c16835260c81c16602082015261230d825180926020908164ffffffffff91828151168552015116910152565bf35b50346106325760403660031901126106325767ffffffffffffffff6004358181116104a35761234290369060040161341b565b9091602490813590811161052b5761235e90369060040161341b565b612369929192613e10565b80840361279c57855b84811061237d578680f35b6123888186886138a7565b35906123958187896138a7565b35885260036020526001600160a01b036040892054166123be6123b98386896138a7565b6138cd565b906123c7613e10565b838a52600960205260ff600160408c20015460a81c161561278657838a52600960205260ff600160408c20015460a01c1661276f578015612758576001600160801b0382161561274157838a5260036020526001600160a01b0360408b205416918282141580612731575b61270d5761243f8561466b565b6001600160801b0381166001600160801b038316116126dd5750908a9291858452600960205260408420926124c56001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff196124a787608094851c614693565b938c8b52600960205260408b2001938454931b16911617815561395f565b6001600160801b036124e981602084015116928260408183511692015116906135a4565b1611156126ac575b86855260096020526001600160a01b0360016040872001541661251e6001600160801b03841685836147f8565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126a2575b612638575b83331415908161262d575b81612622575b506125b0575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612372565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161260a575b8080612579565b612613906134c5565b61261e578738612603565b8780fd5b905083141538612573565b843b1515915061256d565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161268e575b5050612562565b612697906134c5565b61052b578438612687565b50803b151561255d565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124f1565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061273b85614554565b15612432565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a6576108996020916145bd565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c1615612033578061284883613c48565b926005841015611a2b57600260209403612869575b50506040519015158152f35b815260098352604090205460f01c60ff169050388061285d565b503461063257806003193601126106325760206001600160a01b0360085416604051908152f35b503461063257602080600319360112610a5457600435906128c9613e10565b8183526009815260ff600160408520015460a81c1615612033578183526009815260ff600160408520015460a01c1615612a505761290682614554565b15611fe85781600052600381526001600160a01b038060406000205416151580612a48575b80612a2e575b612a16577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260038352604060002054169182159283156129db575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129c3575080f35b60249060405190637e27328960e01b82526004820152fd5b6129fc85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612971565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615612931565b50600061292b565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257612a90366133e6565b60405191602083019383851067ffffffffffffffff861117611a3f57611071946040528584526139b4565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063257602090816003193601126106325760043590612b2c613e10565b818152600980845260ff600160408420015460a81c1615612da85782825280845260408220600181015460a01c60ff1615612b795760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612d9057612ba48260005260096020526001600160a01b0360406000205416331490565b15611fe857612bb282613b65565b93828452818152612bc86002604086200161395f565b926001600160801b03918285511683881610156120075781865283815260ff604087205460f01c1615611fd0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612c31888584818b9c818c9d9c511603169a015116906135a4565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612d76575b01896fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612ce28d84876147f8565b8c612d116040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612d25578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d67575b81818080808480f35b612d70906134c5565b38612d5e565b60018101600160a01b60ff60a01b19825416179055612c75565b6024826040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b5034610632576003199060203683018113610a54576004359167ffffffffffffffff93848411610a545761014090843603011261063257612dfe613e10565b60405193612e0b856134a8565b612e17846004016133d2565b8552612e25602485016133d2565b6020860152612e366044850161356c565b604086015260648401356001600160a01b03811681036104a3576060860152612e616084850161349b565b6080860152612e7260a4850161349b565b60a0860152612e8360c48501613818565b60c086015260e4840135908111610a545783019136602384011215610a54576004830135612eb08161382a565b93612ebe604051958661352e565b8185526024602086019260061b820101933685116106325750602401905b838210612efe57602061163488611629898960e0840152610104369101613878565b82604091612f0c3685613842565b815201910190612edc565b503461063257806003193601126106325760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461063257611071612f64366133e6565b916135d3565b50346106325780600319360112610632576020600754604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657612fc190613c48565b90600582101561140f5760208215838115612fe2575b506040519015158152f35b600191501482612fd7565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c161561203357602091604082828152600985522060ff815460f01c168061307b575b613052575b50506001600160801b0360405191168152f35b61307492506001600160801b03600261306e9201541691613b65565b906135a4565b388061303f565b5060ff600182015460a01c161561303a565b5034610632576040366003190112610632576130a76133a6565b6024356130b381613b21565b33151580613173575b80613149575b6131195781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff604085205416156130c2565b50336001600160a01b03821614156130bc565b5034610632576020366003190112610632576020612266600435613580565b50346106325780600319360112610632576040519080600191600154928360011c9260018516948515613260575b6020958686108114611327578588528794939291879082156113055750506001146132065750506112979250038361352e565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061324857505061129793508201013880611289565b80548389018501528794508693909201918101613230565b93607f16936131d3565b5034610632578060031936011261063257602060405167016345785d8a00008152f35b905034610a54576020366003190112610a54576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613334575b811561330a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613303565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506132fc565b60005b8381106133715750506000910152565b8181015183820152602001613361565b9060209161339a8151809281855285808601910161335e565b601f01601f1916010190565b600435906001600160a01b038216820361062d57565b602435906001600160a01b038216820361062d57565b35906001600160a01b038216820361062d57565b606090600319011261062d576001600160a01b0390600435828116810361062d5791602435908116810361062d579060443590565b9181601f8401121561062d5782359167ffffffffffffffff831161062d576020808501948460051b01011161062d57565b90815180825260208080930193019160005b82811061346c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161345e565b3590811515820361062d57565b610120810190811067ffffffffffffffff821117611a3f57604052565b67ffffffffffffffff8111611a3f57604052565b6040810190811067ffffffffffffffff821117611a3f57604052565b610180810190811067ffffffffffffffff821117611a3f57604052565b6060810190811067ffffffffffffffff821117611a3f57604052565b90601f8019910116810190811067ffffffffffffffff821117611a3f57604052565b67ffffffffffffffff8111611a3f57601f01601f191660200190565b35906001600160801b038216820361062d57565b61358981613b21565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116135bd57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561380057600091848352602091600383526040928284862054161515806137f8575b806137e0575b6137c9578685526003815282848620541694873315159384613719575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876136e1575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136b35750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61370282600052600560205260406000206001600160a01b03198154169055565b87835260048452868320805460001901905561364f565b91929380915090613788575b156137335790878392613626565b848887613750576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156137ad575b806137255750878252600583523384868420541614613725565b5085825260068352848220338352835260ff8583205416613793565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615613609565b506001613603565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361062d57565b67ffffffffffffffff8111611a3f5760051b60200190565b919082604091031261062d5760405161385a816134d9565b602061387381839561386b8161356c565b855201613818565b910152565b919082604091031261062d57604051613890816134d9565b602080829461389e816133d2565b84520135910152565b91908110156138b75760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361062d5790565b9081546138ed8161382a565b926040936138fe604051918261352e565b82815280946020809201926000526020600020906000935b85851061392557505050505050565b60018481928451613935816134d9565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613916565b9060405161396c81613512565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062d5790565b35801515810361062d5790565b91906139c18282856135d3565b803b6139ce575b50505050565b613a2a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613381565b03906020816000938185885af190829082613ac0575b5050613a775782613a4f61463b565b8051919082613a705760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aa85750388080806139c8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613b19575b81613add6020938361352e565b81010312610a545751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106325750903880613a40565b3d9150613ad0565b8060005260036020526001600160a01b03604060002054169081156129c3575090565b8051156138b75760200190565b80518210156138b75760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b8860406000206138e1565b9084846020613b9685613b44565b5101511611613c3e57600052600960205260406000208484825460c81c161115613c2957506001600160801b039081613bce82613b44565b515116946001948594855b613be8575b5050505050505090565b8351871015613c2457828282613bfe8a88613b51565b5101511611613c24578585889981613c17849b89613b51565b5151160116980196613bd9565b613bde565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613c6f575050600490565b805460f81c613cc8575460a01c64ffffffffff164210613cc257613c9281613b65565b9060005260096020526001600160801b038060026040600020015416911610600014613cbd57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613e05575b80613ded575b613dd6579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d9e575b169283613d88575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d64565b613dbf86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d5c565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613cfb565b508181161515613cf5565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e4257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e8e6001600160801b0360408401511660206101008501510151906146ae565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452a57801561450057815180156144d6577f000000000000000000000000000000000000000000000000000000000000000081116144a5575064ffffffffff6020613ef784613b44565b5101511681101561444e5750600090819082815184905b8082106143bd575050505064ffffffffff421664ffffffffff821681101561437d5750506001600160801b0316808203614346575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140aa8951996000198b0190613b51565b51015160c81b169560f01b16911617171717845560005b8181106142a1575050600185016007556001600160a01b036020830151168015613800576140f7866001600160a01b0392613ccf565b16614270576141226001600160a01b036060840151166001600160801b038351169030903390614787565b6001600160801b0360208201511680614240575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661423561421660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141bf8c6134d9565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061344c565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61426a906001600160a01b036060850151166001600160a01b036101008601515116903390614787565b38614136565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142be8160e0870151613b51565b51825468010000000000000000811015611a3f57600181018085558110156138b757600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140c1565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143e1906001600160801b036143d88588613b51565b51511690614693565b9364ffffffffff8060206143f58685613b51565b5101511694168085111561441157506001849301909291613f0e565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061445f84613b44565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614599575b5050821561458757505090565b9091506145943392613580565b161490565b60ff929450906040918152600660205281812033825260205220541691388061457a565b8060005260096020526145d6600260406000200161395f565b816000526009602052604060002060ff600182015460a01c1660001461460957506001600160801b039150602001511690565b5460f81c61461e575061461b90613b65565b90565b61461b91506001600160801b0360408183511692015116906135a4565b3d15614666573d9061464c82613550565b9161465a604051938461352e565b82523d6000602084013e565b606090565b61461b90614678816145bd565b90600052600960205260026040600020015460801c906135a4565b9190916001600160801b03808094169116019182116135bd57565b919091604051906146be826134d9565b600091828152826020820152936001600160801b03928383169182156147685767016345785d8a000080821161473157506146fa8591846148e9565b166020870192818452111561471d57509082614718925116906135a4565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061477c826134d9565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a3f576147f69260405261484d565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147f69161484d60648361352e565b6001600160a01b031690614878600080836020829551910182875af161487161463b565b9084614998565b9081519182151592836148c1575b5050506148905750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a545760200151908115918215036106325750388080614886565b9091906000198382098382029182808310920391808303921461498757670de0b6b3a7640000908183101561495057947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149d757508051156149ad57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614a22575b6149e8575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149e056fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523461001757615f5890816200001d8239f35b600080fdfe600436101561000d57600080fd5b60003560e01c63e9dc63751461002257600080fd5b3461442a57604036600319011261442a576001600160a01b03600435166004350361442a5761022060405260006080819052606060a081905260c082905260e08290526101008190526101208190526101608190526101808190526101a08190526101c0526101e0819052610200526004356001600160a01b038116610140526100ab90614b3b565b610160526100c36004356001600160a01b0316614d53565b61018052610140516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561443757600091614909575b506001600160a01b03610134911680608052614e74565b60a052610140516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576fffffffffffffffffffffffffffffffff916000916148ea575b501660c052610140516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576000906148ad575b6102029150614fc1565b6101a052610140516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156144375760009161487e575b5060c0516fffffffffffffffffffffffffffffffff168015614868576fffffffffffffffffffffffffffffffff6127108193021604166101606080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102d38161499a565b51902061041360296102f563ffffffff61016861ffff8660101c160616615736565b61032363ffffffff601e604660ff6103198460146050848d60081c16060116615736565b9816060116615736565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610363815180926020602488019101614952565b83017f2c00000000000000000000000000000000000000000000000000000000000000602482015261039f825180936020602585019101614952565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103dd8351809460206027868601019101614952565b01017f25290000000000000000000000000000000000000000000000000000000000006027820152036009810184520182614a26565b61044b6fffffffffffffffffffffffffffffffff6040608001511660ff6104446001600160a01b03608051166150bd565b1690615226565b61045f6001600160a01b0360805116614d53565b90602060800151602460206001600160a01b0360c06080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa801561443757602491600091614849575b5060206001600160a01b0360c06080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa8015614437576105259260009161481a575b5064ffffffffff8091169116615571565b610180516101e0519092916105af602161054c6064610545818706615a4f565b9504615736565b6040519481610565879351809260208087019101614952565b820161057a8251809360208085019101614952565b017f25000000000000000000000000000000000000000000000000000000000000006020820152036001810185520183614a26565b6101606080015192610120608001519660e06080015196604051998a61014081011067ffffffffffffffff6101408d01111761444b576101408b016040528a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106bd60c0840151845190615b5b565b906109a461015c604051926106d184614a0a565b600884527f50726f6772657373000000000000000000000000000000000000000000000000602085015261071460405161070a816149b6565b6000815286615a12565b15614812576090945b61072686615736565b916040519586938493661e339034b21e9160c91b60208601526109728351958692610758846027840160208901614952565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b6035858401015261079f8551809660206042888701019101614952565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108a591889160f990910190602001614952565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094091899161015190910190602001614952565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614952565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c81019091520182614a26565b6101008301526101208201526028610120830151604051906109c5826149b6565b60008252610c6b61015c604051926109dc84614a0a565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b610a1882615ed5565b8082111561480a5750945b610a2e878701615736565b91604051958693661e339034b21e9160c91b60208601528151610a58816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a9b825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b9782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c2682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610c4d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810184520182614a26565b610160840152016101808201526028602083015160405190610c8c826149b6565b60008252610cd661015c60405192610ca384614a0a565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b835201602082015261101160808301516030604051610cf4816149b6565b60008152610f9b61015c60405194610d0b86614a0a565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d3e86615e57565b610d4782615ed5565b808211156148025750935b610d5e60288601615736565b91604051978893661e339034b21e9160c91b60208601528151610d88816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dcb825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ec782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f5682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610f7d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810186520184614a26565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e08401526101008301516101608401518451916151bc565b6060820152604051908161010081011067ffffffffffffffff6101008401111761444b57610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161012084015191606081015194604051611167816149d2565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051968761014081011067ffffffffffffffff6101408a01111761444b57610140880160405261011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b01111761444b576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761444b57611cbc611d1d9160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611873615b22565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d1860d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d2200009384604085015280516119a560b88660208501936118e581605e840187614952565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261194a825180936020609385019101614952565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a7820152036098810188520186614a26565b6119ad615b22565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a1381606b8a0184614952565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a58825180936020608e85019101614952565b019082608e830152611a9c60a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b520189614a26565b611be2610108611aaa615b22565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b36815180926020607387019101614952565b8201908760738301526076820152875190611b55826096830188614952565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a614a26565b611bea615b22565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614952565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cfe82518093602060c485019101614952565b019160c483015260c78201520360b8810187520185614a26565b6151bc565b92611d2f611d29614f4f565b89615a12565b9788156147e7575b50604051611d44816149ee565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c08701111761444b576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145c257604051612172816149b6565b60008152995b1561446157604051806101e081011067ffffffffffffffff6101e08301111761444b576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761444b57613b859c612e406036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f119f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612ddc8151809260208a8c019101614952565b8701612df18251809360208a85019101614952565b01612e058251809360208985019101614952565b01612e198251809360208885019101614952565b01612e2d8251809360208785019101614952565b0191820152036016810186520184614a26565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e856026998260208c9451948593019101614952565b8901612e9a8251809360208c85019101614952565b01612eae8251809360208b85019101614952565b01612ec28251809360208a85019101614952565b01612ed68251809360208985019101614952565b01612eea8251809360208885019101614952565b01612efe8251809360208785019101614952565b019182015203600d810189520187614a26565b6137a4604c60e0830151610100840151936135006131336060604084015193015196612f3d8186615d9b565b9461312e61012b604051612f5081614a0a565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fba815180926020603787019101614952565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130fe91849161012090910190602001614952565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b81019091520187614a26565b615d9b565b9561331261012b60405161314681614a0a565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131b0815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132ed82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a520188614a26565b61331c8184615e03565b926134fb61012b60405161332f81614a0a565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613399815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134d682518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810187520185614a26565b615e03565b906136df61012b60405161351381614a0a565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261357d815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136ba82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810185520183614a26565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e0000000000000000000000000000000000000000000000000000006040860152613745815180926020604589019101614952565b840161375b825180936020604585019101614952565b01613770825180936020604585019101614952565b01613785825180936020604585019101614952565b01661e17ba32bc3a1f60c91b604582015203602c810184520182614a26565b613a8461019a6101408401516101a0850151906137e56137df6137d96137d360e060408b01519a015194615736565b94615736565b97615736565b91615736565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e86015261012790613980815180926020858a019101614952565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139ea8251809360208b85019101614952565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a2d8251809360208985019101614952565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a708251809360208785019101614952565b01918201520361017a810185520183614a26565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b10815180926020607b89019101614952565b8401613b26825180936020607b85019101614952565b01613b3b825180936020607b85019101614952565b01613b50825180936020607b85019101614952565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b820152036061810184520182614a26565b610140608001526000806001600160a01b0360c0608001511660405160208101907fb2564569000000000000000000000000000000000000000000000000000000008252602435602482015260248152613bde816149d2565b51915afa613bea614aa9565b61012081905290158015610200526144435760208180518101031261442a5760200151801515810361442a575b151560e05260a051610140516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614437576000916143ec575b506141fd6142ee609461436094613db66089613c936142f997614d53565b92610120608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613cdb815180926020604088019101614952565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613d40825180936020606385019101614952565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d81825180936020608685019101614952565b017f227d5d00000000000000000000000000000000000000000000000000000000006086820152036069810184520182614a26565b6101605160a0516101805160805190926140e79160e39190613de0906001600160a01b0316614d53565b94613dec602435615736565b60e0519096901561436457604051613e03816149ee565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461408360208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613f338160558c0184614952565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613fbd8260b183018a614952565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ff882518093602060c385019101614952565b016140317f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614952565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c782015261406f82518093602060d185019101614952565b019260d184015251809360d5840190614952565b019060d582015261409e82518093602060df85019101614952565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140d88251809360208785019101614952565b010360c3810185520183614a26565b61016051906142586140fa602435615736565b91614179602d604051809560208201976a029b0b13634b2b9102b19160ad1b895261412f815180926020602b87019101614952565b82017f2023000000000000000000000000000000000000000000000000000000000000602b82015261416a8251809360208785019101614952565b0103600d810186520184614a26565b6101c05161418690615887565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a01526141c7815180926020602e8d019101614952565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614952565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614952565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d8201526142b9825180936020609285019101614952565b017f227d0000000000000000000000000000000000000000000000000000000000006092820152036074810184520182614a26565b610100819052615887565b61434c603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000602083015261433c8151809260208686019101614952565b810103601d810184520182614a26565b604051918291602083526020830190614975565b0390f35b6040516143708161499a565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613ec7565b90506020813d60201161442f575b8161440760209383614a26565b8101031261442a5751906001600160a01b038216820361442a57906141fd613c75565b600080fd5b3d91506143fa565b6040513d6000823e3d90fd5b506001613c17565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761444b57610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123c5565b604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612178565b6147fb9198506147f5614f88565b90615a12565b9638611d37565b905093610d52565b905094610a23565b60d09461071d565b61483c915060203d602011614842575b6148348183614a26565b810190614a70565b38610514565b503d61482a565b614862915060203d602011614842576148348183614a26565b386104bd565b634e487b7160e01b600052601260045260246000fd5b6148a0915060203d6020116148a6575b6148988183614a26565b810190614a48565b3861025c565b503d61488e565b506020813d6020116148e2575b816148c760209383614a26565b8101031261442a5751600581101561442a57610202906101f8565b3d91506148ba565b614903915060203d6020116148a6576148988183614a26565b3861019e565b90506020813d60201161494a575b8161492460209383614a26565b8101031261442a57516001600160a01b038116810361442a576001600160a01b0361011d565b3d9150614917565b60005b8381106149655750506000910152565b8181015183820152602001614955565b9060209161498e81518092818552858086019101614952565b601f01601f1916010190565b6080810190811067ffffffffffffffff82111761444b57604052565b6020810190811067ffffffffffffffff82111761444b57604052565b6060810190811067ffffffffffffffff82111761444b57604052565b60c0810190811067ffffffffffffffff82111761444b57604052565b6040810190811067ffffffffffffffff82111761444b57604052565b90601f8019910116810190811067ffffffffffffffff82111761444b57604052565b9081602091031261442a57516fffffffffffffffffffffffffffffffff8116810361442a5790565b9081602091031261442a575164ffffffffff8116810361442a5790565b67ffffffffffffffff811161444b57601f01601f191660200190565b3d15614ad4573d90614aba82614a8d565b91614ac86040519384614a26565b82523d6000602084013e565b606090565b60208183031261442a5780519067ffffffffffffffff821161442a570181601f8201121561442a578051614b0c81614a8d565b92614b1a6040519485614a26565b8184526020828401011161442a57614b389160208085019101614952565b90565b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa928315614d4857600093614d25575b50815192614b7884614a0a565b60118452614bad6020947f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000008682015282615a12565b15614beb5750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614be183614a0a565b600d835282015290565b614c288351614bf981614a0a565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000008682015282615a12565b15614c665750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c5c83614a0a565b600e835282015290565b614ca38351614c7481614a0a565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000008682015282615a12565b15614ce15750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614cd783614a0a565b600f835282015290565b614d219083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614975565b0390fd5b614d4191933d8091833e614d398183614a26565b810190614ad9565b9138614b6b565b82513d6000823e3d90fd5b6001600160a01b03168060405191614d6a836149d2565b602a8352602083016040368237835115614e5e5760309053825160019060011015614e5e57607860218501536029905b808211614de3575050614dab575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614e49577f3031323334353637383961626364656600000000000000000000000000000000901a614e1f8487615a3e565b5360041c918015614e34576000190190614d9a565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b6000809160405160208101906395d89b4160e01b825260048152614e9781614a0a565b51915afa614ea3614aa9565b90158015614f43575b614f095780602080614ec393518301019101614ad9565b601e815111600014614b385750604051614edc81614a0a565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614f1681614a0a565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614eac565b60405190614f5c82614a0a565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f9582614a0a565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b60058110156150a75760048103614fdb5750614b38614f88565b6003810361501d5750604051614ff081614a0a565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b6001810361505f575060405161503281614a0a565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361506e57614b38614f4f565b60405161507a81614a0a565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150f581614a0a565b6000928392839251915afa615108614aa9565b908061513f575b1561513b5760208180518101031261513757602001519060ff82168203615134575090565b80fd5b5080fd5b5090565b50602081511461510f565b6040519061515782614a0a565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061519082614a0a565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906152249294936040519586926020946151de81518092888089019101614952565b84016151f282518093888085019101614952565b0161520582518093878085019101614952565b0161521882518093868085019101614952565b01038085520183614a26565b565b80156155365760009180615511575090505b60019080828110156152a25750505061524f615183565b614b3860226040518361526c829551809260208086019101614952565b81017f20310000000000000000000000000000000000000000000000000000000000006020820152036002810184520182614a26565b66038d7ea4c6800011156154b45760409081519060a0820182811067ffffffffffffffff82111761444b578084526152d9816149b6565b6000815282528251906152eb82614a0a565b8482526020917f4b000000000000000000000000000000000000000000000000000000000000008382015282840152835161532581614a0a565b8581527f4d000000000000000000000000000000000000000000000000000000000000008382015284840152835161535c81614a0a565b8581527f4200000000000000000000000000000000000000000000000000000000000000838201526060840152835161539481614a0a565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615488575b508451946153db86614a0a565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615475575050505061545661545c917f200000000000000000000000000000000000000000000000000000000000000060278701526008865261545186614a0a565b615736565b91615a4f565b916005851015614e5e57614b389460051b0151926151bc565b818101840151888201850152830161540c565b9591926103e8908185106154ab57508680916064600a87040695049301966153c9565b939296506153ce565b50506154be61514a565b614b386028604051836154db829551809260208086019101614952565b81017f203939392e3939540000000000000000000000000000000000000000000000006020820152036008810184520182614a26565b600a0a918215615522575004615238565b80634e487b7160e01b602492526012600452fd5b505060405161554481614a0a565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155d95750615586615183565b614b386026604051836155a3829551809260208086019101614952565b81017f20312044617900000000000000000000000000000000000000000000000000006020820152036006810184520182614a26565b61270f81116156a8576001810361566557614b38602061562d6040516155fe81614a0a565b600481527f20446179000000000000000000000000000000000000000000000000000000008382015293615736565b60405193816156458693518092868087019101614952565b820161565982518093868085019101614952565b01038084520182614a26565b614b38602061562d60405161567981614a0a565b600581527f20446179730000000000000000000000000000000000000000000000000000008382015293615736565b506156b161514a565b614b38602a604051836156ce829551809260208086019101614952565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a810184520182614a26565b9061570e82614a8d565b61571b6040519182614a26565b828152809261572c601f1991614a8d565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615879575b506d04ee2d6d415b85acef81000000008083101561586a575b50662386f26fc100008083101561585b575b506305f5e1008083101561584c575b506127108083101561583d575b50606482101561582d575b600a80921015615823575b6001908160216157ce60018701615704565b95860101905b6157e0575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a83530491821561581e579190826157d4565b6157d9565b91600101916157bc565b91906064600291049101916157b1565b600491939204910191386157a6565b60089193920491019138615799565b6010919392049101913861578a565b60209193920491019138615778565b60409350810491503861575f565b908151156159fd576040519161589c836149d2565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805192600291600285018095116159e75760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159e75761593a9060029694961b615704565b926020840192829183518401976020890192835194600085525b8a811061599a575050505060039394959650525106806001146159875760021461597c575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699615954565b634e487b7160e01b600052601160045260246000fd5b9050604051615a0b816149b6565b6000815290565b9081518151908181149384615a28575050505090565b60209293945082012092012014388080806157d9565b908151811015614e5e570160200190565b80615a615750604051615a0b816149b6565b600a811015615ac657615a7390615736565b614b38602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615ab68151809260208686019101614952565b8101036002810184520182614a26565b615acf90615736565b614b38602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615b128151809260208686019101614952565b8101036001810184520182614a26565b60405190615b2f82614a0a565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d8d57615b69615b22565b906127109081039081116159e757614b3891615b8761013692615736565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615c13815180926020605788019101614952565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c9b82518093602060a785019101614952565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cfc82518093602060d585019101614952565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b61013282015203610116810184520182614a26565b5050604051615a0b816149b6565b6030615224919392936040519481615dbd879351809260208087019101614952565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615df48251809360208785019101614952565b01036010810185520183614a26565b6025615224919392936040519481615e25879351809260208087019101614952565b820164010714051160dd1b6020820152615e488251809360208785019101614952565b01036005810185520183614a26565b60009080518015615ecd57906000916000915b818310615e7c57505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eaf8785615a3e565b511614615ec5575b600d01936001019190615e6a565b849350615eb7565b505050600090565b60009080518015615ecd57906000916000915b818310615efa5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f2d8785615a3e565b511614615f43575b601001936001019190615ee8565b849350615f3556fea164736f6c6343000817000a"; diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index 801b44b51..ebe8f2002 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -76,17 +76,6 @@ contract SablierV2LockupDynamic is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupDynamic - function getRange(uint256 streamId) - external - view - override - notNull(streamId) - returns (LockupDynamic.Range memory range) - { - range = LockupDynamic.Range({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); - } - /// @inheritdoc ISablierV2LockupDynamic function getSegments(uint256 streamId) external @@ -130,6 +119,17 @@ contract SablierV2LockupDynamic is }); } + /// @inheritdoc ISablierV2LockupDynamic + function getTimestamps(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupDynamic.Timestamps memory timestamps) + { + timestamps = LockupDynamic.Timestamps({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -372,7 +372,7 @@ contract SablierV2LockupDynamic is cancelable: params.cancelable, transferable: params.transferable, segments: params.segments, - range: LockupDynamic.Range({ start: stream.startTime, end: stream.endTime }), + timestamps: LockupDynamic.Timestamps({ start: stream.startTime, end: stream.endTime }), broker: params.broker.account }); } diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 6051b7365..a9ca622f4 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -72,21 +72,6 @@ contract SablierV2LockupLinear is cliffTime = _cliffs[streamId]; } - /// @inheritdoc ISablierV2LockupLinear - function getRange(uint256 streamId) - external - view - override - notNull(streamId) - returns (LockupLinear.Range memory range) - { - range = LockupLinear.Range({ - start: _streams[streamId].startTime, - cliff: _cliffs[streamId], - end: _streams[streamId].endTime - }); - } - /// @inheritdoc ISablierV2LockupLinear function getStream(uint256 streamId) external @@ -119,6 +104,21 @@ contract SablierV2LockupLinear is }); } + /// @inheritdoc ISablierV2LockupLinear + function getTimestamps(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupLinear.Timestamps memory timestamps) + { + timestamps = LockupLinear.Timestamps({ + start: _streams[streamId].startTime, + cliff: _cliffs[streamId], + end: _streams[streamId].endTime + }); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -131,17 +131,17 @@ contract SablierV2LockupLinear is returns (uint256 streamId) { // Set the current block timestamp as the stream's start time. - LockupLinear.Range memory range; - range.start = uint40(block.timestamp); + LockupLinear.Timestamps memory timestamps; + timestamps.start = uint40(block.timestamp); // Calculate the cliff time and the end time. It is safe to use unchecked arithmetic because {_create} will // nonetheless check that the end time is greater than the cliff time, and also that the cliff time, if set, // is greater than or equal to the start time. unchecked { if (params.durations.cliff > 0) { - range.cliff = range.start + params.durations.cliff; + timestamps.cliff = timestamps.start + params.durations.cliff; } - range.end = range.start + params.durations.total; + timestamps.end = timestamps.start + params.durations.total; } // Checks, Effects and Interactions: create the stream. @@ -153,7 +153,7 @@ contract SablierV2LockupLinear is asset: params.asset, cancelable: params.cancelable, transferable: params.transferable, - range: range, + timestamps: timestamps, broker: params.broker }) ); @@ -240,7 +240,7 @@ contract SablierV2LockupLinear is Helpers.checkAndCalculateBrokerFee(params.totalAmount, params.broker.fee, MAX_BROKER_FEE); // Check: validate the user-provided parameters. - Helpers.checkCreateLockupLinear(createAmounts.deposit, params.range); + Helpers.checkCreateLockupLinear(createAmounts.deposit, params.timestamps); // Load the stream ID. streamId = nextStreamId; @@ -249,19 +249,19 @@ contract SablierV2LockupLinear is _streams[streamId] = Lockup.Stream({ amounts: Lockup.Amounts({ deposited: createAmounts.deposit, refunded: 0, withdrawn: 0 }), asset: params.asset, - endTime: params.range.end, + endTime: params.timestamps.end, isCancelable: params.cancelable, isDepleted: false, isStream: true, isTransferable: params.transferable, sender: params.sender, - startTime: params.range.start, + startTime: params.timestamps.start, wasCanceled: false }); // Effect: set the cliff time if it is greater than zero. - if (params.range.cliff > 0) { - _cliffs[streamId] = params.range.cliff; + if (params.timestamps.cliff > 0) { + _cliffs[streamId] = params.timestamps.cliff; } // Effect: bump the next stream ID. @@ -291,7 +291,7 @@ contract SablierV2LockupLinear is asset: params.asset, cancelable: params.cancelable, transferable: params.transferable, - range: params.range, + timestamps: params.timestamps, broker: params.broker.account }); } diff --git a/src/SablierV2LockupTranched.sol b/src/SablierV2LockupTranched.sol index d39df2eb6..aaf0105a1 100644 --- a/src/SablierV2LockupTranched.sol +++ b/src/SablierV2LockupTranched.sol @@ -71,17 +71,6 @@ contract SablierV2LockupTranched is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupTranched - function getRange(uint256 streamId) - external - view - override - notNull(streamId) - returns (LockupTranched.Range memory range) - { - range = LockupTranched.Range({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); - } - /// @inheritdoc ISablierV2LockupTranched function getStream(uint256 streamId) external @@ -114,6 +103,17 @@ contract SablierV2LockupTranched is }); } + /// @inheritdoc ISablierV2LockupTranched + function getTimestamps(uint256 streamId) + external + view + override + notNull(streamId) + returns (LockupTranched.Timestamps memory timestamps) + { + timestamps = LockupTranched.Timestamps({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); + } + /// @inheritdoc ISablierV2LockupTranched function getTranches(uint256 streamId) external @@ -276,7 +276,7 @@ contract SablierV2LockupTranched is cancelable: params.cancelable, transferable: params.transferable, tranches: params.tranches, - range: LockupTranched.Range({ start: stream.startTime, end: stream.endTime }), + timestamps: LockupTranched.Timestamps({ start: stream.startTime, end: stream.endTime }), broker: params.broker.account }); } diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index 8931d8845..df77c8f84 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -24,7 +24,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @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 dynamic distribution function. - /// @param range Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps. + /// @param timestamps 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. event CreateLockupDynamicStream( uint256 streamId, @@ -36,7 +36,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { bool cancelable, bool transferable, LockupDynamic.Segment[] segments, - LockupDynamic.Range range, + LockupDynamic.Timestamps timestamps, address broker ); @@ -44,12 +44,6 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the stream's range. - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream ID for the query. - /// @return range See the documentation in {DataTypes}. - function getRange(uint256 streamId) external view returns (LockupDynamic.Range memory range); - /// @notice Retrieves the segments used to compose the dynamic distribution function. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. @@ -61,6 +55,12 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupDynamic.StreamLD memory stream); + /// @notice Retrieves the stream's start and end timestamps. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream ID for the query. + /// @return timestamps See the documentation in {DataTypes}. + function getTimestamps(uint256 streamId) external view returns (LockupDynamic.Timestamps memory timestamps); + /// @notice The maximum number of segments allowed in a stream. /// @dev This is initialized at construction time and cannot be changed later. function MAX_SEGMENT_COUNT() external view returns (uint256); diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol index 11d34e692..425514c09 100644 --- a/src/interfaces/ISablierV2LockupLinear.sol +++ b/src/interfaces/ISablierV2LockupLinear.sol @@ -23,8 +23,8 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Boolean indicating whether the stream will be cancelable or not. /// @param 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 timestamps 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. event CreateLockupLinearStream( uint256 streamId, @@ -35,7 +35,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { IERC20 indexed asset, bool cancelable, bool transferable, - LockupLinear.Range range, + LockupLinear.Timestamps timestamps, address broker ); @@ -49,18 +49,18 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// @param streamId The stream ID for the query. function getCliffTime(uint256 streamId) external view returns (uint40 cliffTime); - /// @notice Retrieves the stream's range. - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream ID for the query. - /// @return range See the documentation in {DataTypes}. - function getRange(uint256 streamId) external view returns (LockupLinear.Range memory range); - /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupLinear.StreamLL memory stream); + /// @notice Retrieves the stream's start, cliff and end timestamps. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream ID for the query. + /// @return timestamps See the documentation in {DataTypes}. + function getTimestamps(uint256 streamId) external view returns (LockupLinear.Timestamps memory timestamps); + /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -80,8 +80,8 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { external returns (uint256 streamId); - /// @notice Creates a stream with the provided start time and end time as the range. The stream is - /// funded by `msg.sender` and is wrapped in an ERC-721 NFT. + /// @notice Creates a stream with the provided start time and end time. The stream is funded by `msg.sender` and is + /// wrapped in an ERC-721 NFT. /// /// @dev Emits a {Transfer} and {CreateLockupLinearStream} event. /// @@ -93,9 +93,10 @@ interface ISablierV2LockupLinear is ISablierV2Lockup { /// - Must not be delegate called. /// - `params.totalAmount` must be greater than zero. /// - If set, `params.broker.fee` must not be greater than `MAX_BROKER_FEE`. - /// - `params.range.start` must be greater than zero and less than `params.range.end`. - /// - If set, `params.range.cliff` must be greater than `params.range.start` and less than `params.range.end`. - /// - `params.range.end` must be in the future. + /// - `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. + /// - If set, `params.timestamps.cliff` must be greater than `params.timestamps.start` and less than + /// `params.timestamps.end`. + /// - `params.timestamps.end` must be in the future. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. /// diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 137aefbb4..836925ccc 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -24,7 +24,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// @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 tranches The tranches the protocol uses to compose the tranched distribution function. - /// @param range Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps. + /// @param timestamps 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. event CreateLockupTranchedStream( uint256 streamId, @@ -36,7 +36,7 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { bool cancelable, bool transferable, LockupTranched.Tranche[] tranches, - LockupTranched.Range range, + LockupTranched.Timestamps timestamps, address broker ); @@ -44,18 +44,18 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the stream's range. - /// @dev Reverts if `streamId` references a null stream. - /// @param streamId The stream ID for the query. - /// @return range See the documentation in {DataTypes}. - function getRange(uint256 streamId) external view returns (LockupTranched.Range memory range); - /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. /// @return stream See the documentation in {DataTypes}. function getStream(uint256 streamId) external view returns (LockupTranched.StreamLT memory stream); + /// @notice Retrieves the stream's start and end timestamps. + /// @dev Reverts if `streamId` references a null stream. + /// @param streamId The stream ID for the query. + /// @return timestamps See the documentation in {DataTypes}. + function getTimestamps(uint256 streamId) external view returns (LockupTranched.Timestamps memory timestamps); + /// @notice Retrieves the tranches used to compose the tranched distribution function. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. diff --git a/src/libraries/Helpers.sol b/src/libraries/Helpers.sol index d112ffa3f..d4bd40b48 100644 --- a/src/libraries/Helpers.sol +++ b/src/libraries/Helpers.sol @@ -143,39 +143,39 @@ library Helpers { } /// @dev Checks the parameters of the {SablierV2LockupLinear-_create} function. - function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Range memory range) internal view { + function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Timestamps memory timestamps) internal view { // Check: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierV2Lockup_DepositAmountZero(); } // Check: the start time is not zero. - if (range.start == 0) { + if (timestamps.start == 0) { revert Errors.SablierV2Lockup_StartTimeZero(); } // Since a cliff time of zero means there is no cliff, the following checks are performed only if it's not zero. - if (range.cliff > 0) { + if (timestamps.cliff > 0) { // Check: the start time is strictly less than the cliff time. - if (range.start >= range.cliff) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(range.start, range.cliff); + if (timestamps.start >= timestamps.cliff) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(timestamps.start, timestamps.cliff); } // Check: the cliff time is strictly less than the end time. - if (range.cliff >= range.end) { - revert Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime(range.cliff, range.end); + if (timestamps.cliff >= timestamps.end) { + revert Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime(timestamps.cliff, timestamps.end); } } // Check: the start time is strictly less than the end time. - if (range.start >= range.end) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(range.start, range.end); + if (timestamps.start >= timestamps.end) { + revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(timestamps.start, timestamps.end); } // Check: the end time is in the future. uint40 blockTimestamp = uint40(block.timestamp); - if (blockTimestamp >= range.end) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, range.end); + if (blockTimestamp >= timestamps.end) { + revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, timestamps.end); } } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 8bbb378c5..c73b01b93 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -147,14 +147,6 @@ library LockupDynamic { Broker broker; } - /// @notice Struct encapsulating the time range. - /// @param start The Unix timestamp indicating the stream's start. - /// @param end The Unix timestamp indicating the stream's end. - struct Range { - uint40 start; - uint40 end; - } - /// @notice Segment struct used in the Lockup Dynamic stream. /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. /// @param exponent The exponent of the segment, denoted as a fixed-point number. @@ -192,6 +184,14 @@ library LockupDynamic { Lockup.Amounts amounts; Segment[] segments; } + + /// @notice Struct encapsulating the LockupDynamic timestamps. + /// @param start The Unix timestamp indicating the stream's start. + /// @param end The Unix timestamp indicating the stream's end. + struct Timestamps { + uint40 start; + uint40 end; + } } /// @notice Namespace for the structs used in {SablierV2LockupLinear}. @@ -228,8 +228,8 @@ library LockupLinear { /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param range Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as Unix - /// timestamps. + /// @param timestamps Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as + /// Unix timestamps. /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { @@ -239,7 +239,7 @@ library LockupLinear { IERC20 asset; bool cancelable; bool transferable; - Range range; + Timestamps timestamps; Broker broker; } @@ -251,16 +251,6 @@ library LockupLinear { uint40 total; } - /// @notice Struct encapsulating the time range. - /// @param start The Unix timestamp for the stream's start. - /// @param cliff The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. - /// @param end The Unix timestamp for the stream's end. - struct Range { - uint40 start; - uint40 cliff; - uint40 end; - } - /// @notice Struct encapsulating the full details of a stream. /// @dev Extends `Lockup.Stream` by including the recipient and the cliff time. struct StreamLL { @@ -277,6 +267,16 @@ library LockupLinear { Lockup.Amounts amounts; uint40 cliffTime; } + + /// @notice Struct encapsulating the LockupLinear timestamps. + /// @param start The Unix timestamp for the stream's start. + /// @param cliff The Unix timestamp for the cliff period's end. A value of zero means there is no cliff. + /// @param end The Unix timestamp for the stream's end. + struct Timestamps { + uint40 start; + uint40 cliff; + uint40 end; + } } /// @notice Namespace for the structs used in {SablierV2LockupTranched}. @@ -330,14 +330,6 @@ library LockupTranched { Broker broker; } - /// @notice Struct encapsulating the time range. - /// @param start The Unix timestamp indicating the stream's start. - /// @param end The Unix timestamp indicating the stream's end. - struct Range { - uint40 start; - uint40 end; - } - /// @notice Struct encapsulating the full details of a stream. /// @dev Extends `Lockup.Stream` by including the recipient and the tranches. struct StreamLT { @@ -355,6 +347,14 @@ library LockupTranched { Tranche[] tranches; } + /// @notice Struct encapsulating the LockupTranched timestamps. + /// @param start The Unix timestamp indicating the stream's start. + /// @param end The Unix timestamp indicating the stream's end. + struct Timestamps { + uint40 start; + uint40 end; + } + /// @notice Tranche struct used in the Lockup Tranched stream. /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals. /// @param timestamp The Unix timestamp indicating the tranche's end. diff --git a/test/fork/LockupDynamic.t.sol b/test/fork/LockupDynamic.t.sol index 65ee2c540..67ccc5e4e 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/fork/LockupDynamic.t.sol @@ -58,8 +58,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { bool isCancelable; bool isDepleted; bool isSettled; - LockupDynamic.Range range; uint256 streamId; + LockupDynamic.Timestamps timestamps; // Create vars uint256 actualBrokerBalance; uint256 actualHolderBalance; @@ -137,8 +137,10 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vars.initialBrokerBalance = vars.balances[1]; vars.streamId = lockupDynamic.nextStreamId(); - vars.range = - LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); + vars.timestamps = LockupDynamic.Timestamps({ + start: params.startTime, + end: params.segments[params.segments.length - 1].timestamp + }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); @@ -154,7 +156,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { cancelable: true, transferable: true, segments: params.segments, - range: vars.range, + timestamps: vars.timestamps, broker: params.broker.account }); @@ -182,7 +184,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, ASSET, "asset"); - assertEq(actualStream.endTime, vars.range.end, "endTime"); + assertEq(actualStream.endTime, vars.timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); @@ -242,7 +244,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { //////////////////////////////////////////////////////////////////////////*/ // Simulate the passage of time. - params.warpTimestamp = boundUint40(params.warpTimestamp, vars.range.start, vars.range.end + 100 seconds); + params.warpTimestamp = + boundUint40(params.warpTimestamp, vars.timestamps.start, vars.timestamps.end + 100 seconds); vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. diff --git a/test/fork/LockupLinear.t.sol b/test/fork/LockupLinear.t.sol index 3bdfb78a8..46fac970d 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/fork/LockupLinear.t.sol @@ -39,7 +39,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { uint128 totalAmount; uint128 withdrawAmount; uint40 warpTimestamp; - LockupLinear.Range range; + LockupLinear.Timestamps timestamps; Broker broker; } @@ -116,19 +116,22 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { Vars memory vars; vars.blockTimestamp = getBlockTimestamp(); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.range.start = - boundUint40(params.range.start, vars.blockTimestamp - 1000 seconds, vars.blockTimestamp + 10_000 seconds); + params.timestamps.start = boundUint40( + params.timestamps.start, vars.blockTimestamp - 1000 seconds, vars.blockTimestamp + 10_000 seconds + ); params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); // The cliff time must be either zero or greater than the start time. - vars.hasCliff = params.range.cliff > 0; + vars.hasCliff = params.timestamps.cliff > 0; if (vars.hasCliff) { - params.range.cliff = - boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); + params.timestamps.cliff = boundUint40( + params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks + ); } // Bound the end time so that it is always greater than the block timestamp, the start time, and the cliff time. - vars.endTimeLowerBound = maxOfThree(params.range.start, params.range.cliff, vars.blockTimestamp); - params.range.end = boundUint40(params.range.end, vars.endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); + vars.endTimeLowerBound = maxOfThree(params.timestamps.start, params.timestamps.cliff, vars.blockTimestamp); + params.timestamps.end = + boundUint40(params.timestamps.end, vars.endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Make the holder the caller. resetPrank(HOLDER); @@ -162,7 +165,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { asset: ASSET, cancelable: true, transferable: true, - range: params.range, + timestamps: params.timestamps, broker: params.broker.account }); @@ -175,7 +178,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { asset: ASSET, cancelable: true, transferable: true, - range: params.range, + timestamps: params.timestamps, broker: params.broker }) ); @@ -184,20 +187,21 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, ASSET, "asset"); - assertEq(actualStream.cliffTime, params.range.cliff, "cliffTime"); - assertEq(actualStream.endTime, params.range.end, "endTime"); + assertEq(actualStream.cliffTime, params.timestamps.cliff, "cliffTime"); + assertEq(actualStream.endTime, params.timestamps.end, "endTime"); assertEq(actualStream.isCancelable, true, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.range.start, "startTime"); + assertEq(actualStream.startTime, params.timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. vars.actualStatus = lockupLinear.statusOf(vars.streamId); - vars.expectedStatus = params.range.start > vars.blockTimestamp ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + vars.expectedStatus = + params.timestamps.start > vars.blockTimestamp ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); // Assert that the next stream ID has been bumped. @@ -236,8 +240,8 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Simulate the passage of time. params.warpTimestamp = boundUint40( params.warpTimestamp, - vars.hasCliff ? params.range.cliff : params.range.start + 1 seconds, - params.range.end + 100 seconds + vars.hasCliff ? params.timestamps.cliff : params.timestamps.start + 1 seconds, + params.timestamps.end + 100 seconds ); vm.warp({ newTimestamp: params.warpTimestamp }); diff --git a/test/fork/LockupTranched.t.sol b/test/fork/LockupTranched.t.sol index 6ae743529..e39f0423d 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/fork/LockupTranched.t.sol @@ -58,8 +58,8 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { bool isCancelable; bool isDepleted; bool isSettled; - LockupTranched.Range range; uint256 streamId; + LockupTranched.Timestamps timestamps; // Create vars uint256 actualBrokerBalance; uint256 actualHolderBalance; @@ -137,7 +137,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { vars.initialBrokerBalance = vars.balances[1]; vars.streamId = lockupTranched.nextStreamId(); - vars.range = LockupTranched.Range({ + vars.timestamps = LockupTranched.Timestamps({ start: params.startTime, end: params.tranches[params.tranches.length - 1].timestamp }); @@ -156,7 +156,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { cancelable: true, transferable: true, tranches: params.tranches, - range: vars.range, + timestamps: vars.timestamps, broker: params.broker.account }); @@ -184,7 +184,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, ASSET, "asset"); - assertEq(actualStream.endTime, vars.range.end, "endTime"); + assertEq(actualStream.endTime, vars.timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); @@ -244,7 +244,8 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { //////////////////////////////////////////////////////////////////////////*/ // Simulate the passage of time. - params.warpTimestamp = boundUint40(params.warpTimestamp, vars.range.start, vars.range.end + 100 seconds); + params.warpTimestamp = + boundUint40(params.warpTimestamp, vars.timestamps.start, vars.timestamps.end + 100 seconds); vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 8d7bbce4f..878150cba 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -125,15 +125,15 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Declare the range. + // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupDynamic.Range memory range = - LockupDynamic.Range({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); + LockupDynamic.Timestamps memory timestamps = + LockupDynamic.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); // Adjust the segments. LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].timestamp = range.start + segmentsWithDurations[0].duration; + segments[0].timestamp = timestamps.start + segmentsWithDurations[0].duration; segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. @@ -156,7 +156,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is cancelable: true, transferable: true, segments: segments, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -166,9 +166,9 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is // Assert that the stream has been created. LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); - expectedStream.endTime = range.end; + expectedStream.endTime = timestamps.end; expectedStream.segments = segments; - expectedStream.startTime = range.start; + expectedStream.startTime = timestamps.start; assertEq(actualStream, expectedStream); // Assert that the stream's status is "STREAMING". diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index b8b2e1843..c804413cf 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -361,7 +361,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is asset: IERC20(asset), cancelable: true, transferable: true, - range: defaults.lockupDynamicRange(), + timestamps: defaults.lockupDynamicTimestamps(), broker: users.broker }); diff --git a/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol b/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol similarity index 54% rename from test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol rename to test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol index 630a1c295..889c0cf50 100644 --- a/test/integration/concrete/lockup-dynamic/get-range/getRange.t.sol +++ b/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol @@ -6,21 +6,21 @@ import { LockupDynamic } from "src/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; -contract GetRange_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test { +contract GetTimestamps_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockupDynamic.getRange(nullStreamId); + lockupDynamic.getTimestamps(nullStreamId); } modifier givenNotNull() { _; } - function test_GetRange() external givenNotNull { + function test_GetTimestamps() external givenNotNull { uint256 streamId = createDefaultStream(); - LockupDynamic.Range memory actualRange = lockupDynamic.getRange(streamId); - LockupDynamic.Range memory expectedRange = defaults.lockupDynamicRange(); - assertEq(actualRange, expectedRange); + LockupDynamic.Timestamps memory actualTimestamps = lockupDynamic.getTimestamps(streamId); + LockupDynamic.Timestamps memory expectedTimestamps = defaults.lockupDynamicTimestamps(); + assertEq(actualTimestamps, expectedTimestamps); } } diff --git a/test/integration/concrete/lockup-tranched/get-range/getRange.tree b/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree similarity index 65% rename from test/integration/concrete/lockup-tranched/get-range/getRange.tree rename to test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree index 61e44d77a..49e6bf2a0 100644 --- a/test/integration/concrete/lockup-tranched/get-range/getRange.tree +++ b/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree @@ -1,5 +1,5 @@ -getRange.t.sol +getTimestamps.t.sol ├── given the ID references a null stream │ └── it should revert └── given the ID does not reference a null stream - └── it should return the correct range + └── it should return the correct timestamps diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index c6d16323d..38fd9daae 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -87,9 +87,9 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Declare the range. + // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupLinear.Range memory range = LockupLinear.Range({ + LockupLinear.Timestamps memory timestamps = LockupLinear.Timestamps({ start: blockTimestamp, cliff: blockTimestamp + defaults.CLIFF_DURATION(), end: blockTimestamp + defaults.TOTAL_DURATION() @@ -114,7 +114,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is asset: dai, cancelable: true, transferable: true, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -124,9 +124,9 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Assert that the stream has been created. LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.startTime = range.start; - expectedStream.cliffTime = range.cliff; - expectedStream.endTime = range.end; + expectedStream.startTime = timestamps.start; + expectedStream.cliffTime = timestamps.cliff; + expectedStream.endTime = timestamps.end; assertEq(actualStream, expectedStream); // Assert that the stream's status is "STREAMING". diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index eeb709aeb..5ce293a85 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -56,7 +56,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is uint40 endTime = defaults.END_TIME(); vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); - createDefaultStreamWithRange(LockupLinear.Range({ start: 0, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: 0, cliff: cliffTime, end: endTime })); } function test_RevertWhen_StartTimeNotLessThanEndTime() @@ -75,7 +75,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime ) ); - createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: 0, end: endTime })); + createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: 0, end: endTime })); } function test_CreateWithTimestamps_StartTimeLessThanEndTime() @@ -86,8 +86,8 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenStartTimeNotZero whenCliffTimeZero { - createDefaultStreamWithRange( - LockupLinear.Range({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) + createDefaultStreamWithTimestamps( + LockupLinear.Timestamps({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) ); // Assert that the stream has been created. @@ -124,7 +124,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime ) ); - createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } function test_RevertWhen_CliffTimeNotLessThanEndTime() @@ -144,7 +144,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime ) ); - createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } function test_RevertGiven_EndTimeNotInTheFuture() @@ -265,7 +265,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is asset: IERC20(asset), cancelable: true, transferable: true, - range: defaults.lockupLinearRange(), + timestamps: defaults.lockupLinearTimestamps(), broker: users.broker }); diff --git a/test/integration/concrete/lockup-linear/get-range/getRange.t.sol b/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol similarity index 54% rename from test/integration/concrete/lockup-linear/get-range/getRange.t.sol rename to test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol index 6e71a3522..a0de39a5e 100644 --- a/test/integration/concrete/lockup-linear/get-range/getRange.t.sol +++ b/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol @@ -6,21 +6,21 @@ import { LockupLinear } from "src/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; -contract GetRange_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test { +contract GetTimestamps_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockupLinear.getRange(nullStreamId); + lockupLinear.getTimestamps(nullStreamId); } modifier givenNotNull() { _; } - function test_GetRange() external givenNotNull { + function test_GetTimestamps() external givenNotNull { uint256 streamId = createDefaultStream(); - LockupLinear.Range memory actualRange = lockupLinear.getRange(streamId); - LockupLinear.Range memory expectedRange = defaults.lockupLinearRange(); - assertEq(actualRange, expectedRange); + LockupLinear.Timestamps memory actualTimestamps = lockupLinear.getTimestamps(streamId); + LockupLinear.Timestamps memory expectedTimestamps = defaults.lockupLinearTimestamps(); + assertEq(actualTimestamps, expectedTimestamps); } } diff --git a/test/integration/concrete/lockup-dynamic/get-range/getRange.tree b/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree similarity index 65% rename from test/integration/concrete/lockup-dynamic/get-range/getRange.tree rename to test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree index 61e44d77a..49e6bf2a0 100644 --- a/test/integration/concrete/lockup-dynamic/get-range/getRange.tree +++ b/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree @@ -1,5 +1,5 @@ -getRange.t.sol +getTimestamps.t.sol ├── given the ID references a null stream │ └── it should revert └── given the ID does not reference a null stream - └── it should return the correct range + └── it should return the correct timestamps diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 24097a17f..32d71c6b3 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -119,14 +119,14 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is // Make the Sender the stream's funder address funder = users.sender; - // Declare the range. + // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupTranched.Range memory range = - LockupTranched.Range({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); + LockupTranched.Timestamps memory timestamps = + LockupTranched.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); LockupTranched.Tranche[] memory tranches = defaults.tranches(); - tranches[0].timestamp = range.start + tranchesWithDurations[0].duration; + tranches[0].timestamp = timestamps.start + tranchesWithDurations[0].duration; tranches[1].timestamp = tranches[0].timestamp + tranchesWithDurations[1].duration; tranches[2].timestamp = tranches[1].timestamp + tranchesWithDurations[2].duration; @@ -150,7 +150,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is cancelable: true, transferable: true, tranches: tranches, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -160,8 +160,8 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is // Assert that the stream has been created. LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); - expectedStream.endTime = range.end; - expectedStream.startTime = range.start; + expectedStream.endTime = timestamps.end; + expectedStream.startTime = timestamps.start; expectedStream.tranches = tranches; assertEq(actualStream, expectedStream); diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 7519eca56..cb1ce9a56 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -361,7 +361,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is asset: IERC20(asset), cancelable: true, transferable: true, - range: defaults.lockupTranchedRange(), + timestamps: defaults.lockupTranchedTimestamps(), broker: users.broker }); diff --git a/test/integration/concrete/lockup-tranched/get-range/getRange.t.sol b/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol similarity index 54% rename from test/integration/concrete/lockup-tranched/get-range/getRange.t.sol rename to test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol index 12db5b22a..3205fd3ed 100644 --- a/test/integration/concrete/lockup-tranched/get-range/getRange.t.sol +++ b/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol @@ -6,21 +6,21 @@ import { LockupTranched } from "src/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; -contract GetRange_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { +contract GetTimestamps_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockupTranched.getRange(nullStreamId); + lockupTranched.getTimestamps(nullStreamId); } modifier givenNotNull() { _; } - function test_GetRange() external givenNotNull { + function test_GetTimestamps() external givenNotNull { uint256 streamId = createDefaultStream(); - LockupTranched.Range memory actualRange = lockupTranched.getRange(streamId); - LockupTranched.Range memory expectedRange = defaults.lockupTranchedRange(); - assertEq(actualRange, expectedRange); + LockupTranched.Timestamps memory actualTimestamps = lockupTranched.getTimestamps(streamId); + LockupTranched.Timestamps memory expectedTimestamps = defaults.lockupTranchedTimestamps(); + assertEq(actualTimestamps, expectedTimestamps); } } diff --git a/test/integration/concrete/lockup-linear/get-range/getRange.tree b/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree similarity index 65% rename from test/integration/concrete/lockup-linear/get-range/getRange.tree rename to test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree index 61e44d77a..49e6bf2a0 100644 --- a/test/integration/concrete/lockup-linear/get-range/getRange.tree +++ b/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree @@ -1,5 +1,5 @@ -getRange.t.sol +getTimestamps.t.sol ├── given the ID references a null stream │ └── it should revert └── given the ID does not reference a null stream - └── it should return the correct range + └── it should return the correct timestamps diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 49dee2114..bb5b9b334 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -64,9 +64,9 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is expectCallToTransferFrom({ from: vars.funder, to: users.broker, value: vars.createAmounts.brokerFee }); } - // Create the range struct. + // Create the timestamps struct. vars.segmentsWithTimestamps = getSegmentsWithTimestamps(segments); - LockupDynamic.Range memory range = LockupDynamic.Range({ + LockupDynamic.Timestamps memory timestamps = LockupDynamic.Timestamps({ start: getBlockTimestamp(), end: vars.segmentsWithTimestamps[vars.segmentsWithTimestamps.length - 1].timestamp }); @@ -83,7 +83,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is cancelable: true, transferable: true, segments: vars.segmentsWithTimestamps, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -103,7 +103,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.endTime, timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); @@ -111,7 +111,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.recipient, users.recipient, "recipient"); assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); - assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.startTime, timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index bbedfef03..44cfe385a 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -226,8 +226,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockupDynamic) }); - LockupDynamic.Range memory range = - LockupDynamic.Range({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); + LockupDynamic.Timestamps memory timestamps = LockupDynamic.Timestamps({ + start: params.startTime, + end: params.segments[params.segments.length - 1].timestamp + }); emit CreateLockupDynamicStream({ streamId: streamId, funder: funder, @@ -238,7 +240,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is cancelable: params.cancelable, transferable: params.transferable, segments: params.segments, - range: range, + timestamps: timestamps, broker: params.broker.account }); @@ -266,7 +268,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.endTime, timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); @@ -274,7 +276,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.segments, params.segments, "segments"); - assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.startTime, timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol index 50c78efef..9fa96dd32 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -66,8 +66,8 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); - // Create the range struct by calculating the start time, cliff time and the end time. - LockupLinear.Range memory range = LockupLinear.Range({ + // Create the timestamps struct by calculating the start time, cliff time and the end time. + LockupLinear.Timestamps memory timestamps = LockupLinear.Timestamps({ start: getBlockTimestamp(), cliff: durations.cliff == 0 ? 0 : getBlockTimestamp() + durations.cliff, end: getBlockTimestamp() + durations.total @@ -84,7 +84,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is asset: dai, cancelable: true, transferable: true, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -94,9 +94,9 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Assert that the stream has been created. LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.cliffTime = range.cliff; - expectedStream.endTime = range.end; - expectedStream.startTime = range.start; + expectedStream.cliffTime = timestamps.cliff; + expectedStream.endTime = timestamps.end; + expectedStream.startTime = timestamps.start; assertEq(actualStream, expectedStream); // Assert that the stream's status is "STREAMING". diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 444a0e7e9..d59318ec1 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -69,7 +69,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime ) ); - createDefaultStreamWithRange(LockupLinear.Range({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } struct Vars { @@ -110,18 +110,21 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is { vm.assume(funder != address(0) && params.recipient != address(0) && params.broker.account != address(0)); vm.assume(params.totalAmount != 0); - params.range.start = - boundUint40(params.range.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); + params.timestamps.start = + boundUint40(params.timestamps.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.transferable = true; // The cliff time must be either zero or greater than the start time. - if (params.range.cliff > 0) { - params.range.cliff = - boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); - params.range.end = boundUint40(params.range.end, params.range.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); + if (params.timestamps.cliff > 0) { + params.timestamps.cliff = boundUint40( + params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks + ); + params.timestamps.end = + boundUint40(params.timestamps.end, params.timestamps.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); } else { - params.range.end = boundUint40(params.range.end, params.range.start + 1 seconds, MAX_UNIX_TIMESTAMP); + params.timestamps.end = + boundUint40(params.timestamps.end, params.timestamps.start + 1 seconds, MAX_UNIX_TIMESTAMP); } // Calculate the fee amounts and the deposit amount. @@ -158,7 +161,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is asset: dai, cancelable: params.cancelable, transferable: params.transferable, - range: params.range, + timestamps: params.timestamps, broker: params.broker.account }); @@ -171,7 +174,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is asset: dai, cancelable: params.cancelable, transferable: params.transferable, - range: params.range, + timestamps: params.timestamps, broker: params.broker }) ); @@ -180,20 +183,21 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.cliffTime, params.range.cliff, "cliffTime"); - assertEq(actualStream.endTime, params.range.end, "endTime"); + assertEq(actualStream.cliffTime, params.timestamps.cliff, "cliffTime"); + assertEq(actualStream.endTime, params.timestamps.end, "endTime"); assertEq(actualStream.isCancelable, params.cancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.range.start, "startTime"); + assertEq(actualStream.startTime, params.timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. vars.actualStatus = lockupLinear.statusOf(streamId); - vars.expectedStatus = params.range.start > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + vars.expectedStatus = + params.timestamps.start > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 2a50e7a21..c70594e0b 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -64,9 +64,9 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is expectCallToTransferFrom({ from: vars.funder, to: users.broker, value: vars.createAmounts.brokerFee }); } - // Create the range struct. + // Create the timestamps struct. vars.tranchesWithTimestamps = getTranchesWithTimestamps(tranches); - LockupTranched.Range memory range = LockupTranched.Range({ + LockupTranched.Timestamps memory timestamps = LockupTranched.Timestamps({ start: getBlockTimestamp(), end: vars.tranchesWithTimestamps[vars.tranchesWithTimestamps.length - 1].timestamp }); @@ -83,7 +83,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is cancelable: true, transferable: true, tranches: vars.tranchesWithTimestamps, - range: range, + timestamps: timestamps, broker: users.broker }); @@ -103,7 +103,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.endTime, timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); @@ -111,7 +111,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.tranches, vars.tranchesWithTimestamps, "tranches"); assertEq(actualStream.sender, users.sender, "sender"); - assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.startTime, timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index a81214e25..31d7a2122 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -227,7 +227,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockupTranched) }); - LockupTranched.Range memory range = LockupTranched.Range({ + LockupTranched.Timestamps memory timestamps = LockupTranched.Timestamps({ start: params.startTime, end: params.tranches[params.tranches.length - 1].timestamp }); @@ -241,7 +241,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is cancelable: params.cancelable, transferable: params.transferable, tranches: params.tranches, - range: range, + timestamps: timestamps, broker: params.broker.account }); @@ -269,7 +269,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, range.end, "endTime"); + assertEq(actualStream.endTime, timestamps.end, "endTime"); assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isStream"); assertEq(actualStream.isStream, true, "isStream"); @@ -277,7 +277,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is assertEq(actualStream.recipient, params.recipient, "recipient"); assertEq(actualStream.sender, params.sender, "sender"); assertEq(actualStream.tranches, params.tranches, "tranches"); - assertEq(actualStream.startTime, range.start, "startTime"); + assertEq(actualStream.startTime, timestamps.start, "startTime"); assertEq(actualStream.wasCanceled, false, "wasCanceled"); // Assert that the stream's status is correct. diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol index f5809e894..941620ada 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -102,14 +102,6 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided range. - function createDefaultStreamWithRange(LockupDynamic.Range memory range) internal returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = range.start; - params.segments[1].timestamp = range.end; - streamId = lockupDynamic.createWithTimestamps(params); - } - /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; @@ -141,6 +133,17 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh streamId = lockupDynamic.createWithTimestamps(params); } + /// @dev Creates the default stream with the provided timestamps. + function createDefaultStreamWithTimestamps(LockupDynamic.Timestamps memory timestamps) + internal + returns (uint256 streamId) + { + LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.startTime = timestamps.start; + params.segments[1].timestamp = timestamps.end; + streamId = lockupDynamic.createWithTimestamps(params); + } + /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/integration/shared/lockup-linear/LockupLinear.t.sol index 0dd6b92ee..c7344ac45 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/integration/shared/lockup-linear/LockupLinear.t.sol @@ -75,14 +75,7 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.range.end = endTime; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided range. - function createDefaultStreamWithRange(LockupLinear.Range memory range) internal returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.range = range; + params.timestamps.end = endTime; streamId = lockupLinear.createWithTimestamps(params); } @@ -103,7 +96,17 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha /// @inheritdoc Lockup_Integration_Shared_Test function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.range.start = startTime; + params.timestamps.start = startTime; + streamId = lockupLinear.createWithTimestamps(params); + } + + /// @dev Creates the default stream with the provided timestamps. + function createDefaultStreamWithTimestamps(LockupLinear.Timestamps memory timestamps) + internal + returns (uint256 streamId) + { + LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; + params.timestamps = timestamps; streamId = lockupLinear.createWithTimestamps(params); } diff --git a/test/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/integration/shared/lockup-tranched/LockupTranched.t.sol index 73d97ec2f..97a39415f 100644 --- a/test/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -111,11 +111,14 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S streamId = lockupTranched.createWithTimestamps(params); } - /// @dev Creates the default stream with the provided range. - function createDefaultStreamWithRange(LockupTranched.Range memory range) internal returns (uint256 streamId) { + /// @dev Creates the default stream with the provided timestamps. + function createDefaultStreamWithTimestamps(LockupTranched.Timestamps memory timestamps) + internal + returns (uint256 streamId) + { LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = range.start; - params.tranches[1].timestamp = range.end; + params.startTime = timestamps.start; + params.tranches[1].timestamp = timestamps.end; streamId = lockupTranched.createWithTimestamps(params); } diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index ff8e3ac4f..1d69be7bf 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -94,18 +94,19 @@ contract LockupLinearCreateHandler is BaseHandler { uint40 blockTimestamp = getBlockTimestamp(); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.range.start = boundUint40(params.range.start, 1 seconds, blockTimestamp); + params.timestamps.start = boundUint40(params.timestamps.start, 1 seconds, blockTimestamp); params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); // The cliff time must be either zero or greater than the start time. - if (params.range.cliff > 0) { - params.range.cliff = - boundUint40(params.range.cliff, params.range.start + 1 seconds, params.range.start + 52 weeks); + if (params.timestamps.cliff > 0) { + params.timestamps.cliff = boundUint40( + params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks + ); } // Bound the end time so that it is always greater than the start time, the cliff time, and the block timestamp. - uint40 endTimeLowerBound = maxOfThree(params.range.start, params.range.cliff, blockTimestamp); - params.range.end = boundUint40(params.range.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); + uint40 endTimeLowerBound = maxOfThree(params.timestamps.start, params.timestamps.cliff, blockTimestamp); + params.timestamps.end = boundUint40(params.timestamps.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index 7b2be5b81..492f2f678 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -87,23 +87,23 @@ abstract contract Assertions is PRBMathAssertions { assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); } - /// @dev Compares two {LockupDynamic.Range} struct entities. - function assertEq(LockupDynamic.Range memory a, LockupDynamic.Range memory b) internal { - assertEqUint40(a.end, b.end, "range.end"); - assertEqUint40(a.start, b.start, "range.start"); + /// @dev Compares two {LockupDynamic.Timestamps} struct entities. + function assertEq(LockupDynamic.Timestamps memory a, LockupDynamic.Timestamps memory b) internal { + assertEqUint40(a.end, b.end, "timestamps.end"); + assertEqUint40(a.start, b.start, "timestamps.start"); } - /// @dev Compares two {LockupLinear.Range} struct entities. - function assertEq(LockupLinear.Range memory a, LockupLinear.Range memory b) internal { - assertEqUint40(a.cliff, b.cliff, "range.cliff"); - assertEqUint40(a.end, b.end, "range.end"); - assertEqUint40(a.start, b.start, "range.start"); + /// @dev Compares two {LockupLinear.Timestamps} struct entities. + function assertEq(LockupLinear.Timestamps memory a, LockupLinear.Timestamps memory b) internal { + assertEqUint40(a.cliff, b.cliff, "timestamps.cliff"); + assertEqUint40(a.end, b.end, "timestamps.end"); + assertEqUint40(a.start, b.start, "timestamps.start"); } - /// @dev Compares two {LockupTranched.Range} struct entities. - function assertEq(LockupTranched.Range memory a, LockupTranched.Range memory b) internal { - assertEqUint40(a.end, b.end, "range.end"); - assertEqUint40(a.start, b.start, "range.start"); + /// @dev Compares two {LockupTranched.Timestamps} struct entities. + function assertEq(LockupTranched.Timestamps memory a, LockupTranched.Timestamps memory b) internal { + assertEqUint40(a.end, b.end, "timestamps.end"); + assertEqUint40(a.start, b.start, "timestamps.start"); } /// @dev Compares two {LockupDynamic.Segment} arrays. diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index b39e36998..62e990ac0 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -84,10 +84,6 @@ contract Defaults is Constants { return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } - function lockupDynamicRange() public view returns (LockupDynamic.Range memory) { - return LockupDynamic.Range({ start: START_TIME, end: END_TIME }); - } - function lockupDynamicStream() public view returns (LockupDynamic.StreamLD memory) { return LockupDynamic.StreamLD({ amounts: lockupAmounts(), @@ -105,8 +101,8 @@ contract Defaults is Constants { }); } - function lockupLinearRange() public view returns (LockupLinear.Range memory) { - return LockupLinear.Range({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); + function lockupDynamicTimestamps() public view returns (LockupDynamic.Timestamps memory) { + return LockupDynamic.Timestamps({ start: START_TIME, end: END_TIME }); } function lockupLinearStream() public view returns (LockupLinear.StreamLL memory) { @@ -126,8 +122,8 @@ contract Defaults is Constants { }); } - function lockupTranchedRange() public view returns (LockupTranched.Range memory) { - return LockupTranched.Range({ start: START_TIME, end: END_TIME }); + function lockupLinearTimestamps() public view returns (LockupLinear.Timestamps memory) { + return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); } function lockupTranchedStream() public view returns (LockupTranched.StreamLT memory) { @@ -147,6 +143,10 @@ contract Defaults is Constants { }); } + function lockupTranchedTimestamps() public view returns (LockupTranched.Timestamps memory) { + return LockupTranched.Timestamps({ start: START_TIME, end: END_TIME }); + } + function segments() public view returns (LockupDynamic.Segment[] memory segments_) { segments_ = new LockupDynamic.Segment[](2); segments_[0] = ( @@ -263,7 +263,7 @@ contract Defaults is Constants { asset: asset, cancelable: true, transferable: true, - range: lockupLinearRange(), + timestamps: lockupLinearTimestamps(), broker: broker() }); } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index aeaf08220..9822f1a7b 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -63,7 +63,7 @@ abstract contract Events { bool cancelable, bool transferable, LockupDynamic.Segment[] segments, - LockupDynamic.Range range, + LockupDynamic.Timestamps timestamps, address broker ); @@ -80,12 +80,12 @@ abstract contract Events { IERC20 indexed asset, bool cancelable, bool transferable, - LockupLinear.Range range, + LockupLinear.Timestamps timestamps, address broker ); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHED + SABLIER-V2-LOCKUP-TRANCHED //////////////////////////////////////////////////////////////////////////*/ event CreateLockupTranchedStream( @@ -98,7 +98,7 @@ abstract contract Events { bool cancelable, bool transferable, LockupTranched.Tranche[] tranches, - LockupTranched.Range range, + LockupTranched.Timestamps timestamps, address broker ); } From c85c66ac0a3f3f287ba10a5c267c1ce67d1b6aeb Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Sat, 11 May 2024 16:17:36 +0300 Subject: [PATCH 096/132] style: place _update under non-constant header closes #919 --- src/abstracts/SablierV2Lockup.sol | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index e386f0c93..c7b848101 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -509,35 +509,6 @@ abstract contract SablierV2Lockup is return _calculateStreamedAmount(streamId); } - /// @notice Overrides the {ERC-721._update} function to check that the stream is transferable, and emits an - /// ERC-4906 event. - /// @dev There are two cases when the transferable flag is ignored: - /// - If the current owner is 0, then the update is a mint and is allowed. - /// - If `to` is 0, then the update is a burn and is also allowed. - /// @param to The address of the new recipient of the stream. - /// @param streamId ID of the stream to update. - /// @param auth Optional parameter. If the value is not zero, the overridden implementation will check that - /// `auth` is either the recipient of the stream, or an approved third party. - /// @return The original recipient of the `streamId` before the update. - function _update( - address to, - uint256 streamId, - address auth - ) - internal - override - updateMetadata(streamId) - returns (address) - { - address from = _ownerOf(streamId); - - if (from != address(0) && to != address(0) && !_streams[streamId].isTransferable) { - revert Errors.SablierV2Lockup_NotTransferable(streamId); - } - - return super._update(to, streamId, auth); - } - /// @dev See the documentation for the user-facing functions that call this internal function. function _withdrawableAmountOf(uint256 streamId) internal view returns (uint128) { return _streamedAmountOf(streamId) - _streams[streamId].amounts.withdrawn; @@ -627,6 +598,35 @@ abstract contract SablierV2Lockup is _streams[streamId].isCancelable = false; } + /// @notice Overrides the {ERC-721._update} function to check that the stream is transferable, and emits an + /// ERC-4906 event. + /// @dev There are two cases when the transferable flag is ignored: + /// - If the current owner is 0, then the update is a mint and is allowed. + /// - If `to` is 0, then the update is a burn and is also allowed. + /// @param to The address of the new recipient of the stream. + /// @param streamId ID of the stream to update. + /// @param auth Optional parameter. If the value is not zero, the overridden implementation will check that + /// `auth` is either the recipient of the stream, or an approved third party. + /// @return The original recipient of the `streamId` before the update. + function _update( + address to, + uint256 streamId, + address auth + ) + internal + override + updateMetadata(streamId) + returns (address) + { + address from = _ownerOf(streamId); + + if (from != address(0) && to != address(0) && !_streams[streamId].isTransferable) { + revert Errors.SablierV2Lockup_NotTransferable(streamId); + } + + return super._update(to, streamId, auth); + } + /// @dev See the documentation for the user-facing functions that call this internal function. function _withdraw(uint256 streamId, address to, uint128 amount) internal { // Effect: update the withdrawn amount. From 2e8a620a345fb649dd807d69ff695635061de392 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 14 May 2024 12:10:50 +0100 Subject: [PATCH 097/132] test: adds gas benchmarking tests, automates max values for segment & tranches (#908) * test: add gas benchmarks * test(benchmark): optimize markdown file * style: prettier check * test(benchmark): benchmarks for create functions for various segments and tranches * refactor(benchmark): move common logic to Benchmark.t.sol * test: set MAX_SEGMENT_COUNT and MAX_TRANCHE_COUNT to very high * test(benchmark): refactor some function names * feat: script for estimating the max segment and the tranche counts * feat: declare variables to map max segment and max tranche counts with chain id * test: use precompile values for MAX_SEGMENT_COUNT and MAX_TRANCHE_COUNT in precompile tests * feat: Add MAX_COUNT for Arbitrum chain id * chore: rebase staging branch * refactor: address PR feedback * refactor: move count map to a separate function * test: subtract 1M from block gas limit to calculate max counts * refactor: updated max count values * refactor: improvements * build: add benchmark foundry profile build: correct package json benchmark script build: remove package json gas report and snapshot scripts refactor: move all benchmark solidity files test: add isBenchmarkProfile function chore: remove .gas.snapshot file * test: use default broker fee in benchmark * build: remove no match tests in package json scripts chore: run "bun run prettier:write" * refactor: remove benchmarks dir * feat: add more benchmarks chore: address shub feedback * style: print table in update-script-counts bash script * test: profile.benchmark * test(benchmark): alphabetical order test(benchmark): remove redundant functions docs(benchmark): reorder table rows chore: refactor * refactor: small improvements --------- Co-authored-by: Paul Razvan Berg Co-authored-by: andreivladbrg --- .gas-snapshot | 610 ------------------- benchmark/Benchmark.t.sol | 177 ++++++ benchmark/EstimateMaxCount.t.sol | 91 +++ benchmark/LockupDynamic.Gas.t.sol | 237 +++++++ benchmark/LockupLinear.Gas.t.sol | 125 ++++ benchmark/LockupTranched.Gas.t.sol | 229 +++++++ benchmark/results/SablierV2LockupDynamic.md | 31 + benchmark/results/SablierV2LockupLinear.md | 19 + benchmark/results/SablierV2LockupTranched.md | 31 + foundry.toml | 7 +- package.json | 4 +- precompiles/Precompiles.sol | 4 +- script/Base.s.sol | 73 ++- shell/update-script-counts.sh | 58 ++ test/Base.t.sol | 2 +- test/utils/Defaults.sol | 4 +- test/utils/Precompiles.t.sol | 6 +- test/utils/Utils.sol | 6 + 18 files changed, 1083 insertions(+), 631 deletions(-) delete mode 100644 .gas-snapshot create mode 100644 benchmark/Benchmark.t.sol create mode 100644 benchmark/EstimateMaxCount.t.sol create mode 100644 benchmark/LockupDynamic.Gas.t.sol create mode 100644 benchmark/LockupLinear.Gas.t.sol create mode 100644 benchmark/LockupTranched.Gas.t.sol create mode 100644 benchmark/results/SablierV2LockupDynamic.md create mode 100644 benchmark/results/SablierV2LockupLinear.md create mode 100644 benchmark/results/SablierV2LockupTranched.md create mode 100755 shell/update-script-counts.sh diff --git a/.gas-snapshot b/.gas-snapshot deleted file mode 100644 index 48f3def76..000000000 --- a/.gas-snapshot +++ /dev/null @@ -1,610 +0,0 @@ -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 89750) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 80588) -Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 80577) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 81703) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11307) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89997) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14290) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19526) -Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19453) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 91993) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 82826) -Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 82815) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 83947) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11293) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 82797) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14276) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19512) -Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19439) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 100824) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 91657) -Burn_LockupTranched_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 91646) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 92794) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11337) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 89957) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14320) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19556) -Burn_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19483) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 825245) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6337) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32154) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 834317) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12441) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78346) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 326099) -CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 917533) -CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 1187323, ~: 1187205) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 605322) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6354) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 34350) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 635539) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12455) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 80386) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 254304) -CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 718807) -CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 871449, ~: 873846) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple() (gas: 781440) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6376) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 41732) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 934139) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12477) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 87761) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 343238) -CancelMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 1028115) -CancelMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 76, μ: 1187817, ~: 1189876) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 374065) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 357198) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97570) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 359078) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 357765) -Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 72608) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11306) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86793) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63162) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26730) -Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 246547) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 439285, ~: 441871) -Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 73205, ~: 73472) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 279367) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 262476) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 79988) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 264351) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 263043) -Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 74697) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11295) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79602) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65415) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 28898) -Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 192697) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 318154, ~: 319467) -Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 75294, ~: 75561) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel() (gas: 363179) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 346235) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 87417) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 348154) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 346802) -Cancel_LockupTranched_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 82125) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11339) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 86762) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74218) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 36302) -Cancel_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 273651) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 76, μ: 403616, ~: 406077) -Cancel_LockupTranched_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 76, μ: 82722, ~: 82989) -Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5054235) -Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 3901281) -Constructor_LockupTranched_Integration_Concrete_Test:test_Constructor() (gas: 4102534) -CreateWithDurations_LockupDynamic_Integration_Concrete_Test:test_CreateWithDurations() (gas: 357047) -CreateWithDurations_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint64,uint40)[]) (runs: 76, μ: 4638758, ~: 4576850) -CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 286201) -CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 59, μ: 284174, ~: 284666) -CreateWithDurations_LockupTranched_Integration_Concrete_Test:test_CreateWithDurations() (gas: 387411) -CreateWithDurations_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint128,uint40)[]) (runs: 76, μ: 4727005, ~: 4774224) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 350026) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 356447) -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 38801) -CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint64,uint40)[],(address,uint256))) (runs: 76, μ: 3840986, ~: 4093877) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 284913) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 291268) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_CreateWithTimestamps_StartTimeLessThanEndTime() (gas: 242528) -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 33024) -CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256))) (runs: 74, μ: 401117, ~: 409850) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps() (gas: 377367) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_CreateWithTimestamps_AssetMissingReturnValue() (gas: 383788) -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41670) -CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test:testFuzz_CreateWithTimestamps(address,(address,address,uint128,address,bool,bool,uint40,(uint128,uint40)[],(address,uint256))) (runs: 75, μ: 3975411, ~: 3912867) -GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 16028) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 279107) -GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12005) -GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 227792) -GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11991) -GetAsset_LockupTranched_Integration_Concrete_Test:test_GetAsset() (gas: 304673) -GetAsset_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12013) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 228455) -GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11435) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 282044) -GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11659) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 230681) -GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11633) -GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 307632) -GetDepositedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11689) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 281886) -GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11559) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 230593) -GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11567) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_GetEndTime() (gas: 307496) -GetEndTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11611) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 15697) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 67673) -GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11458) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 15677) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 69911) -GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11438) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_GetRecipient() (gas: 15705) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 78742) -GetRecipient_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11466) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 311818) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 301586) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 306861) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 306832) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 346191) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 348047) -GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11935) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 258782) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 248283) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 253558) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 253529) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 289702) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 291485) -GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11921) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 340410) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 327152) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 332427) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 332398) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 369687) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 371506) -GetRefundedAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11943) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 283577) -GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13735) -GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 278914) -GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11791) -GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 227593) -GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11771) -GetSender_LockupTranched_Integration_Concrete_Test:test_GetSender() (gas: 304480) -GetSender_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11799) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 282061) -GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11823) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 230746) -GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11809) -GetStartTime_LockupTranched_Integration_Concrete_Test:test_GetStartTime() (gas: 307627) -GetStartTime_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11831) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 276912) -GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 64313) -GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15777) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 52571) -GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 54618) -GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14546) -GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream() (gas: 303573) -GetStream_LockupTranched_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 68952) -GetStream_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15775) -GetTimestamps_LockupDynamic_Integration_Concrete_Test:test_GetTimestamps() (gas: 277498) -GetTimestamps_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12552) -GetTimestamps_LockupLinear_Integration_Concrete_Test:test_GetTimestamps() (gas: 227179) -GetTimestamps_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12744) -GetTimestamps_LockupTranched_Integration_Concrete_Test:test_GetTimestamps() (gas: 303107) -GetTimestamps_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12560) -GetTranches_LockupTranched_Integration_Concrete_Test:test_GetTranches() (gas: 310004) -GetTranches_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13541) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 356043) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 304825) -GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11934) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 359016, ~: 359242) -GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 306500, ~: 306758) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 275393) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 253522) -GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11920) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 278623, ~: 278432) -GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 255142, ~: 255455) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 357065) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 330391) -GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11942) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 76, μ: 360235, ~: 360098) -GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 76, μ: 332057, ~: 332324) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 483969) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 305109) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 298835) -IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11294) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 384875) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 254006) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 247567) -IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11318) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable() (gas: 533279) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 332234) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 324435) -IsCancelable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 344999) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 311551) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 299621) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 305461) -IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 321700) -IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11602) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 288561) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 258573) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 248376) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 254376) -IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 254797) -IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11645) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 368545) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 340200) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 325244) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 332604) -IsCold_LockupTranched_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 333051) -IsCold_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11654) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 310963) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 298184) -IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 257950) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 246904) -IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11182) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted() (gas: 339577) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 323772) -IsDepleted_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 298566) -IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 11624) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 247283) -IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 11645) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream() (gas: 324129) -IsStream_LockupTranched_Integration_Concrete_Test:test_IsStream_Null() (gas: 11632) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 298712) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11711) -IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 483846) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 247454) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11754) -IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 384777) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 324300) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11741) -IsTransferable_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 533144) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 344467) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 311040) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 299017) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 304957) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 321190) -IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11118) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 288020) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 258046) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 247756) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 253866) -IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 254271) -IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11161) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 367960) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 339629) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 324580) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 332050) -IsWarm_LockupTranched_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 332481) -IsWarm_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11126) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 20114) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 19754) -MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupTranched() (gas: 20518) -MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 947952) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 311027) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 304862) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 304855) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 311717) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 344402) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 347622) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 489144) -RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11121) -RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 43844, ~: 31437) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 258007) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 253550) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 253737) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 255180) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 287929) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 291076) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 390055) -RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 33544, ~: 33767) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 339613) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 331773) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 331944) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 333122) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 367892) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 371075) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 538414) -RefundableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11132) -RefundableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 76, μ: 42270, ~: 42531) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 674472) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 667569) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 279362) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 672786) -Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 668132) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11633) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87157) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 63595) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24780) -Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 628630) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 527634) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 520699) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 228116) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 525908) -Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 521262) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11641) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 79979) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 65870) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 26958) -Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 481724) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce() (gas: 750314) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 743379) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 307733) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 749964) -Renounce_LockupTranched_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 743942) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11641) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87095) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 74629) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 34318) -Renounce_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 702973) -SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 15233) -SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_DecimalsNotImplemented() (gas: 14011) -SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_EOA() (gas: 12384) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol() (gas: 21211) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 65033) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13573) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 549340) -SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 15218) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6641536) -SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2174048) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6641956) -SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2174368) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6651179) -SetNFTDescriptor_LockupTranched_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2183733) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11661) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 321826) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 311680) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 305640) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 299695) -StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 345117) -StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11669) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 254225) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 258656) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 254519) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 248404) -StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 288640) -StatusOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11691) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf() (gas: 332488) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 340296) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 332760) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 325285) -StatusOf_LockupTranched_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 368637) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11363) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 46690) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestampNot1st() (gas: 51557) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 243119) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20956) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 26298) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 64589) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 21041) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 27328) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88231) -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111997) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 76, μ: 3429088, ~: 3280853) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 76, μ: 3944273, ~: 4547498) -StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 75, μ: 275057, ~: 269182) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11327) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 29011) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 22523) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 29919) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 66798) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 23037) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 29528) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 81054) -StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 104714) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 75, μ: 250415, ~: 249688) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 76, μ: 30089, ~: 30298) -StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 75, μ: 257278, ~: 258128) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11371) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf() (gas: 44607) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_CurrentTimestamp1st() (gas: 35775) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 30316) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 35658) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 75623) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 30423) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 36932) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 88236) -StreamedAmountOf_LockupTranched_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 111898) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint40)[],uint40) (runs: 76, μ: 3763594, ~: 4155368) -StreamedAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint40)[],uint40,uint40) (runs: 76, μ: 3923618, ~: 3973167) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13971) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) -TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) -TokenURI_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13954) -TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) -TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) -TokenURI_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13976) -TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624) -TokenURI_LockupTranched_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6623) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 281658) -TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 294732) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 229833) -TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 243419) -TransferFrom_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 307376) -TransferFrom_LockupTranched_Integration_Concrete_Test:test_TransferFrom() (gas: 320306) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12019) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 315616) -WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 299008) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12040) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 262376) -WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 247728) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12027) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled() (gas: 342619) -WasCanceled_LockupTranched_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 324574) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 358719) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 329120) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 329235) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 332598) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 351465) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 321888) -WithdrawHooks_LockupDynamic_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 325497) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 291226) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 261612) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 261748) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 265100) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 283978) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 254387) -WithdrawHooks_LockupLinear_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 258005) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerApprovedOperator() (gas: 372130) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerRecipient() (gas: 342516) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerSender() (gas: 342652) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_CallerUnknown() (gas: 346004) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerApprovedOperator() (gas: 364887) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerSender() (gas: 335296) -WithdrawHooks_LockupTranched_Integration_Concrete_Test:test_WithdrawHooks_SenderHook_CallerUnknown() (gas: 338914) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72289) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14117) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 249989) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 161875) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 97681) -WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 133982, ~: 112931) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 74548) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14115) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 196188) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 116747) -WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99986) -WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 106745, ~: 115227) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 83373) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14137) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 277105) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 127008) -WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 108767) -WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 76, μ: 116105, ~: 125476) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 138996) -WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80608) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 123460, ~: 124010) -WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 83174, ~: 83318) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 80273) -WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 82893) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 78577, ~: 78666) -WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 85432, ~: 85603) -WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax() (gas: 91922) -WithdrawMax_LockupTranched_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 91733) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 76, μ: 88760, ~: 88907) -WithdrawMax_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 76, μ: 94326, ~: 94443) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73486) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20712) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124779) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 82981) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 274574) -WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6560) -WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 2705346, ~: 2705247) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 75652) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20614) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 109248) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 85147) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 227852) -WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6549) -WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 1995659, ~: 1995523) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 84497) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 20700) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124125) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 93992) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 251733) -WithdrawMultiple_LockupTranched_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 6608) -WithdrawMultiple_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,uint128) (runs: 76, μ: 2887114, ~: 2886990) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19851) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 65278) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 355888) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 113693) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 84175) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 85081) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 69772) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 297839) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 355321) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 109264) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 376666) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 355919) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 323286) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 297802) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 297324) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 85810) -Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 129362) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 75, μ: 131584, ~: 103286) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 149175, ~: 149175) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 76, μ: 4168893, ~: 4262966) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 75, μ: 162688, ~: 162616) -Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 107201, ~: 107201) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19826) -Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67517) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 274746) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 96012) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 66489) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 67395) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 71955) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 230324) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 274177) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 77933) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 281848) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 274775) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 242105) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 230288) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 229810) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 68124) -Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 111719) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 76, μ: 106164, ~: 105979) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 117855, ~: 117855) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 76, μ: 144928, ~: 144763) -Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 75848, ~: 75848) -Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19833) -Withdraw_LockupTranched_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 76283) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw() (gas: 357079) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 103407) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 73884) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_CallerUnknownAddress() (gas: 74790) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 79361) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_GoodSender() (gas: 311246) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 356510) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 86736) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 365555) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 357108) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_ReentrancySender() (gas: 324404) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_RevertingSender() (gas: 311210) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderDoesNotImplementHook() (gas: 310732) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_SenderNotContract() (gas: 75519) -Withdraw_LockupTranched_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 119206) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 75, μ: 117647, ~: 117488) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 76, μ: 126652, ~: 126652) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 75, μ: 152434, ~: 152254) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_TrancheFuzzing(((uint128,uint40)[],uint256,address)) (runs: 76, μ: 3694638, ~: 3705862) -Withdraw_LockupTranched_Integration_Fuzz_Test:testFuzz_Withdraw_UnknownCaller(address) (runs: 76, μ: 84673, ~: 84673) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12001) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 347109) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 316668) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 306103) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 312711) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 302873) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 309141) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 347177) -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 349327) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 76, μ: 319238, ~: 302486) -WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 76, μ: 289334, ~: 278476) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11965) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 246950) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 254408) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 259672) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 249588) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 256049) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 290663) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 292740) -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 277907) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 76, μ: 474541, ~: 473581) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 76, μ: 254619, ~: 254819) -WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 76, μ: 450630, ~: 449585) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12009) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 364800) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 338398) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 333018) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 341300) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 329788) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 336234) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 370670) -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 372783) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 76, μ: 329511, ~: 329114) -WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 76, μ: 304390, ~: 304292) \ No newline at end of file diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol new file mode 100644 index 000000000..94417c9bf --- /dev/null +++ b/benchmark/Benchmark.t.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { ISablierV2Lockup } from "../src/interfaces/ISablierV2Lockup.sol"; + +import { Base_Test } from "../test/Base.t.sol"; + +/// @notice Benchmark contract with common logic needed by all tests. +abstract contract Benchmark_Test is Base_Test { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + uint128 internal immutable AMOUNT_PER_SEGMENT = 100e18; + uint128 internal immutable AMOUNT_PER_TRANCHE = 100e18; + uint256[7] internal streamIds = [50, 51, 52, 53, 54, 55, 56]; + + /// @dev The directory where the benchmark files are stored. + string internal benchmarkResults = "benchmark/results/"; + + /// @dev The path to the file where the benchmark results are stored. + string internal benchmarkResultsFile; + + string internal contentToAppend; + + ISablierV2Lockup internal lockup; + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + super.setUp(); + + deal({ token: address(dai), to: users.sender, give: type(uint256).max }); + resetPrank({ msgSender: users.sender }); + + // Create the first streams in each Lockup contract to initialize all the variables. + _createFewStreams(); + } + + /*////////////////////////////////////////////////////////////////////////// + GAS FUNCTIONS FOR SHARED IMPLEMENTATIONS + //////////////////////////////////////////////////////////////////////////*/ + + function gasBurn() internal { + // Set the caller to the Recipient for `burn` and change timestamp to the end time. + resetPrank({ msgSender: users.recipient }); + + vm.warp({ newTimestamp: defaults.END_TIME() }); + + lockup.withdrawMax(streamIds[0], users.recipient); + + uint256 beforeGas = gasleft(); + lockup.burn(streamIds[0]); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat("| `burn` | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCancel() internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time + resetPrank({ msgSender: users.sender }); + + uint256 beforeGas = gasleft(); + lockup.cancel(streamIds[1]); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat("| `cancel` | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasRenounce() internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + uint256 beforeGas = gasleft(); + lockup.renounce(streamIds[2]); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat("| `renounce` | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasWithdraw(uint256 streamId, address caller, address to, string memory extraInfo) internal { + resetPrank({ msgSender: caller }); + + uint128 withdrawAmount = lockup.withdrawableAmountOf(streamId); + + uint256 beforeGas = gasleft(); + lockup.withdraw(streamId, to, withdrawAmount); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + // Check if caller is recipient or not. + bool isCallerRecipient = caller == users.recipient; + + string memory s = isCallerRecipient + ? string.concat("| `withdraw` ", extraInfo, " (by Recipient) | ") + : string.concat("| `withdraw` ", extraInfo, " (by Anyone) | "); + contentToAppend = string.concat(s, gasUsed, " |"); + + // Append the data to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasWithdraw_AfterEndTime(uint256 streamId, address caller, address to, string memory extraInfo) internal { + extraInfo = string.concat(extraInfo, " (After End Time)"); + + uint256 warpTime = lockup.getEndTime(streamId) + 1; + vm.warp({ newTimestamp: warpTime }); + + gasWithdraw(streamId, caller, to, extraInfo); + } + + function gasWithdraw_BeforeEndTime( + uint256 streamId, + address caller, + address to, + string memory extraInfo + ) + internal + { + extraInfo = string.concat(extraInfo, " (Before End Time)"); + + uint256 warpTime = lockup.getEndTime(streamId) - 1; + vm.warp({ newTimestamp: warpTime }); + + gasWithdraw(streamId, caller, to, extraInfo); + } + + function gasWithdraw_ByAnyone(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { + gasWithdraw_AfterEndTime(streamId1, users.sender, users.recipient, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.sender, users.recipient, extraInfo); + } + + function gasWithdraw_ByRecipient(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { + gasWithdraw_AfterEndTime(streamId1, users.recipient, users.alice, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.recipient, users.alice, extraInfo); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Append a line to the file at given path. + function _appendToFile(string memory path, string memory line) internal { + vm.writeLine({ path: path, data: line }); + } + + /// @dev Calculates the total amount to be deposited in the stream, by accounting for the broker fee. + function _calculateTotalAmount(uint128 depositAmount, UD60x18 brokerFee) internal pure returns (uint128) { + UD60x18 factor = ud(1e18); + UD60x18 totalAmount = ud(depositAmount).mul(factor).div(factor.sub(brokerFee)); + return totalAmount.intoUint128(); + } + + /// @dev Internal function to creates a few streams in each Lockup contract. + function _createFewStreams() internal { + for (uint128 i = 0; i < 100; ++i) { + lockupDynamic.createWithTimestamps(defaults.createWithTimestampsLD()); + lockupLinear.createWithTimestamps(defaults.createWithTimestampsLL()); + lockupTranched.createWithTimestamps(defaults.createWithTimestampsLT()); + } + } +} diff --git a/benchmark/EstimateMaxCount.t.sol b/benchmark/EstimateMaxCount.t.sol new file mode 100644 index 000000000..006ed36cc --- /dev/null +++ b/benchmark/EstimateMaxCount.t.sol @@ -0,0 +1,91 @@ +// solhint-disable no-console +pragma solidity >=0.8.22 <0.9.0; + +import { console2 } from "forge-std/src/console2.sol"; +import { Test } from "forge-std/src/Test.sol"; + +import { LockupDynamic_Gas_Test } from "./LockupDynamic.Gas.t.sol"; +import { LockupTranched_Gas_Test } from "./LockupTranched.Gas.t.sol"; + +/// @notice Structure to group the block gas limit and chain id. +struct ChainInfo { + uint256 blockGasLimit; + uint256 chainId; +} + +contract EstimateMaxCount is Test { + // Buffer gas units to be deducted from the block gas limit so that the max count never exceeds the block limit. + uint256 public constant BUFFER_GAS = 1_000_000; + + // Initial guess for the maximum number of segments/tranches. + uint128 public constant INITIAL_GUESS = 240; + + /// @dev List of chains with their block gas limit. + ChainInfo[] public chains; + + constructor() { + chains.push(ChainInfo({ blockGasLimit: 32_000_000, chainId: 42_161 })); // Arbitrum + chains.push(ChainInfo({ blockGasLimit: 15_000_000, chainId: 43_114 })); // Avalanche + chains.push(ChainInfo({ blockGasLimit: 60_000_000, chainId: 8453 })); // Base + chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 238 })); // Blast + chains.push(ChainInfo({ blockGasLimit: 138_000_000, chainId: 56 })); // BSC + chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 1 })); // Ethereum + chains.push(ChainInfo({ blockGasLimit: 17_000_000, chainId: 100 })); // Gnosis + chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 10 })); // Optimism + chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 137 })); // Polygon + chains.push(ChainInfo({ blockGasLimit: 10_000_000, chainId: 534_352 })); // Scroll + chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 11_155_111 })); // Sepolia + } + + /// @notice Estimate the maximum number of segments allowed in LockupDynamic. + function test_EstimateSegments() public { + LockupDynamic_Gas_Test lockupDynamicGasTest = new LockupDynamic_Gas_Test(); + lockupDynamicGasTest.setUp(); + + for (uint256 i = 0; i < chains.length; ++i) { + uint128 count = INITIAL_GUESS; + + // Subtract `BUFFER_GAS` from `blockGasLimit` as an additional precaution to account for the dynamic gas for + // ether transfer on different chains. + uint256 blockGasLimit = chains[i].blockGasLimit - BUFFER_GAS; + + uint256 gasConsumed = 0; + uint256 lastGasConsumed = 0; + while (blockGasLimit > gasConsumed) { + count += 10; + lastGasConsumed = gasConsumed; + + // Estimate the gas consumed by adding 10 segments. + gasConsumed = lockupDynamicGasTest.computeGas_CreateWithDurations(count + 10); + } + + console2.log("count: %d and gasUsed: %d and chainId: %d", count, lastGasConsumed, chains[i].chainId); + } + } + + /// @notice Estimate the maximum number of tranches allowed in LockupTranched. + function test_EstimateTranches() public { + LockupTranched_Gas_Test lockupTranchedGasTest = new LockupTranched_Gas_Test(); + lockupTranchedGasTest.setUp(); + + for (uint256 i = 0; i < chains.length; ++i) { + uint128 count = INITIAL_GUESS; + + // Subtract `BUFFER_GAS` from `blockGasLimit` as an additional precaution to account for the dynamic gas for + // ether transfer on different chains. + uint256 blockGasLimit = chains[i].blockGasLimit - BUFFER_GAS; + + uint256 gasConsumed = 0; + uint256 lastGasConsumed = 0; + while (blockGasLimit > gasConsumed) { + count += 10; + lastGasConsumed = gasConsumed; + + // Estimate the gas consumed by adding 10 tranches. + gasConsumed = lockupTranchedGasTest.computeGas_CreateWithDurations(count + 10); + } + + console2.log("count: %d and gasUsed: %d and chainId: %d", count, lastGasConsumed, chains[i].chainId); + } + } +} diff --git a/benchmark/LockupDynamic.Gas.t.sol b/benchmark/LockupDynamic.Gas.t.sol new file mode 100644 index 000000000..afac9403d --- /dev/null +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ud2x18 } from "@prb/math/src/UD2x18.sol"; +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; + +import { Broker, LockupDynamic } from "../src/types/DataTypes.sol"; +import { Benchmark_Test } from "./Benchmark.t.sol"; + +/// @notice Tests used to benchmark LockupDynamic. +/// @dev This contract creates a Markdown file with the gas usage of each function. +contract LockupDynamic_Gas_Test is Benchmark_Test { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + uint128[] internal _segments = [2, 10, 100]; + uint256[] internal _streamIdsForWithdraw = new uint256[](4); + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + function setUp() public override { + super.setUp(); + + lockup = lockupDynamic; + } + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function testGas_Implementations() external { + // Set the file path. + benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupDynamic.md"); + + // Create the file if it doesn't exist, otherwise overwrite it. + vm.writeFile({ + path: benchmarkResultsFile, + data: string.concat("# Benchmarks for LockupDynamic\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") + }); + + vm.warp({ newTimestamp: defaults.END_TIME() }); + gasBurn(); + + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + gasCancel(); + + gasRenounce(); + + // Create streams with different number of segments. + for (uint256 i; i < _segments.length; ++i) { + gasCreateWithDurations({ totalSegments: _segments[i] }); + gasCreateWithTimestamps({ totalSegments: _segments[i] }); + + gasWithdraw_ByRecipient( + _streamIdsForWithdraw[0], + _streamIdsForWithdraw[1], + string.concat("(", vm.toString(_segments[i]), " segments)") + ); + gasWithdraw_ByAnyone( + _streamIdsForWithdraw[2], + _streamIdsForWithdraw[3], + string.concat("(", vm.toString(_segments[i]), " segments)") + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + GAS BENCHMARKS FOR CREATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + // The following function is used in the estimations of `MAX_SEGMENT_COUNT`. + function computeGas_CreateWithDurations(uint128 totalSegments) public returns (uint256 gasUsed) { + LockupDynamic.CreateWithDurations memory params = + _createWithDurationParams(totalSegments, defaults.BROKER_FEE()); + + uint256 beforeGas = gasleft(); + lockupDynamic.createWithDurations(params); + + gasUsed = beforeGas - gasleft(); + } + + function gasCreateWithDurations(uint128 totalSegments) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + LockupDynamic.CreateWithDurations memory params = + _createWithDurationParams(totalSegments, defaults.BROKER_FEE()); + + uint256 beforeGas = gasleft(); + lockupDynamic.createWithDurations(params); + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurations` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Calculate gas usage without broker fee. + params = _createWithDurationParams(totalSegments, ud(0)); + + beforeGas = gasleft(); + lockupDynamic.createWithDurations(params); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurations` (", vm.toString(totalSegments), " segments) (Broker fee not set) | ", gasUsed, " |" + ); + + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Store the last 2 streams IDs for withdraw gas benchmark. + _streamIdsForWithdraw[0] = lockupDynamic.nextStreamId() - 2; + _streamIdsForWithdraw[1] = lockupDynamic.nextStreamId() - 1; + + // Create 2 more streams for withdraw gas benchmark. + _streamIdsForWithdraw[2] = lockupDynamic.createWithDurations(params); + _streamIdsForWithdraw[3] = lockupDynamic.createWithDurations(params); + } + + function gasCreateWithTimestamps(uint128 totalSegments) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time + resetPrank({ msgSender: users.sender }); + + LockupDynamic.CreateWithTimestamps memory params = + _createWithTimestampParams(totalSegments, defaults.BROKER_FEE()); + + uint256 beforeGas = gasleft(); + lockupDynamic.createWithTimestamps(params); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestamps` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" + ); + + // Append the data to the file + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Calculate gas usage without broker fee. + params = _createWithTimestampParams(totalSegments, ud(0)); + + beforeGas = gasleft(); + lockupDynamic.createWithTimestamps(params); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestamps` (", + vm.toString(totalSegments), + " segments) (Broker fee not set) | ", + gasUsed, + " |" + ); + + // Append the data to the file + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function _createWithDurationParams( + uint128 totalSegments, + UD60x18 brokerFee + ) + private + view + returns (LockupDynamic.CreateWithDurations memory) + { + LockupDynamic.SegmentWithDuration[] memory segments_ = new LockupDynamic.SegmentWithDuration[](totalSegments); + + // Populate segments. + for (uint256 i = 0; i < totalSegments; ++i) { + segments_[i] = ( + LockupDynamic.SegmentWithDuration({ + amount: AMOUNT_PER_SEGMENT, + exponent: ud2x18(0.5e18), + duration: defaults.CLIFF_DURATION() + }) + ); + } + + uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; + + return LockupDynamic.CreateWithDurations({ + sender: users.sender, + recipient: users.recipient, + totalAmount: _calculateTotalAmount(depositAmount, brokerFee), + asset: dai, + cancelable: true, + transferable: true, + segments: segments_, + broker: Broker({ account: users.broker, fee: brokerFee }) + }); + } + + function _createWithTimestampParams( + uint128 totalSegments, + UD60x18 brokerFee + ) + private + view + returns (LockupDynamic.CreateWithTimestamps memory) + { + LockupDynamic.Segment[] memory segments_ = new LockupDynamic.Segment[](totalSegments); + + // Populate segments. + for (uint256 i = 0; i < totalSegments; ++i) { + segments_[i] = ( + LockupDynamic.Segment({ + amount: AMOUNT_PER_SEGMENT, + exponent: ud2x18(0.5e18), + timestamp: getBlockTimestamp() + uint40(defaults.CLIFF_DURATION() * (1 + i)) + }) + ); + } + + uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; + + return LockupDynamic.CreateWithTimestamps({ + sender: users.sender, + recipient: users.recipient, + totalAmount: _calculateTotalAmount(depositAmount, brokerFee), + asset: dai, + cancelable: true, + transferable: true, + startTime: getBlockTimestamp(), + segments: segments_, + broker: Broker({ account: users.broker, fee: brokerFee }) + }); + } +} diff --git a/benchmark/LockupLinear.Gas.t.sol b/benchmark/LockupLinear.Gas.t.sol new file mode 100644 index 000000000..f4d35e961 --- /dev/null +++ b/benchmark/LockupLinear.Gas.t.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ud } from "@prb/math/src/UD60x18.sol"; + +import { LockupLinear } from "../src/types/DataTypes.sol"; + +import { Benchmark_Test } from "./Benchmark.t.sol"; + +/// @notice Tests used to benchmark LockupLinear. +/// @dev This contract creates a Markdown file with the gas usage of each function. +contract LockupLinear_Gas_Test is Benchmark_Test { + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public override { + super.setUp(); + + lockup = lockupLinear; + } + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function testGas_Implementations() external { + // Set the file path. + benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupLinear.md"); + + // Create the file if it doesn't exist, otherwise overwrite it. + vm.writeFile({ + path: benchmarkResultsFile, + data: string.concat("# Benchmarks for LockupLinear\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") + }); + + vm.warp({ newTimestamp: defaults.END_TIME() }); + gasBurn(); + + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + gasCancel(); + + gasRenounce(); + + gasCreateWithDurations({ cliffDuration: 0 }); + gasCreateWithDurations({ cliffDuration: defaults.CLIFF_DURATION() }); + + gasCreateWithTimestamps({ cliffTime: 0 }); + gasCreateWithTimestamps({ cliffTime: defaults.CLIFF_TIME() }); + + gasWithdraw_ByRecipient(streamIds[3], streamIds[4], ""); + gasWithdraw_ByAnyone(streamIds[5], streamIds[6], ""); + } + + /*////////////////////////////////////////////////////////////////////////// + GAS BENCHMARKS FOR CREATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function gasCreateWithDurations(uint40 cliffDuration) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + LockupLinear.CreateWithDurations memory params = defaults.createWithDurationsLL(); + params.durations.cliff = cliffDuration; + + uint256 beforeGas = gasleft(); + lockupLinear.createWithDurations(params); + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + string memory cliffSetOrNot = cliffDuration == 0 ? " (cliff not set)" : " (cliff set)"; + + contentToAppend = string.concat("| `createWithDurations` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Calculate gas usage without broker fee. + params.broker.fee = ud(0); + params.totalAmount = _calculateTotalAmount(defaults.DEPOSIT_AMOUNT(), ud(0)); + + beforeGas = gasleft(); + lockupLinear.createWithDurations(params); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = + string.concat("| `createWithDurations` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithTimestamps(uint40 cliffTime) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); + params.timestamps.cliff = cliffTime; + + uint256 beforeGas = gasleft(); + lockupLinear.createWithTimestamps(params); + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + string memory cliffSetOrNot = cliffTime == 0 ? " (cliff not set)" : " (cliff set)"; + + contentToAppend = + string.concat("| `createWithTimestamps` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Calculate gas usage without broker fee. + params.broker.fee = ud(0); + params.totalAmount = _calculateTotalAmount(defaults.DEPOSIT_AMOUNT(), ud(0)); + + beforeGas = gasleft(); + lockupLinear.createWithTimestamps(params); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = + string.concat("| `createWithTimestamps` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } +} diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol new file mode 100644 index 000000000..591e80c89 --- /dev/null +++ b/benchmark/LockupTranched.Gas.t.sol @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; + +import { Broker, LockupTranched } from "../src/types/DataTypes.sol"; + +import { Benchmark_Test } from "./Benchmark.t.sol"; + +/// @notice Tests used to benchmark LockupTranched. +/// @dev This contract creates a Markdown file with the gas usage of each function. +contract LockupTranched_Gas_Test is Benchmark_Test { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + uint128[] internal _tranches = [2, 10, 100]; + uint256[] internal _streamIdsForWithdraw = new uint256[](4); + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public override { + super.setUp(); + + lockup = lockupTranched; + } + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function testGas_Implementations() external { + // Set the file path. + benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupTranched.md"); + + // Create the file if it doesn't exist, otherwise overwrite it. + vm.writeFile({ + path: benchmarkResultsFile, + data: string.concat( + "# Benchmarks for LockupTranched\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + ) + }); + + vm.warp({ newTimestamp: defaults.END_TIME() }); + gasBurn(); + + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + gasCancel(); + + gasRenounce(); + + // Create streams with different number of tranches. + for (uint256 i; i < _tranches.length; ++i) { + gasCreateWithDurations({ totalTranches: _tranches[i] }); + gasCreateWithTimestamps({ totalTranches: _tranches[i] }); + + gasWithdraw_ByRecipient( + _streamIdsForWithdraw[0], + _streamIdsForWithdraw[1], + string.concat("(", vm.toString(_tranches[i]), " tranches)") + ); + gasWithdraw_ByAnyone( + _streamIdsForWithdraw[2], + _streamIdsForWithdraw[3], + string.concat("(", vm.toString(_tranches[i]), " tranches)") + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + GAS BENCHMARKS FOR CREATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + // The following function is used in the estimation of `MAX_TRANCHE_COUNT` + function computeGas_CreateWithDurations(uint128 totalTranches) public returns (uint256 gasUsed) { + LockupTranched.CreateWithDurations memory params = + _createWithDurationParams(totalTranches, defaults.BROKER_FEE()); + + uint256 beforeGas = gasleft(); + lockupTranched.createWithDurations(params); + + gasUsed = beforeGas - gasleft(); + } + + function gasCreateWithDurations(uint128 totalTranches) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + LockupTranched.CreateWithDurations memory params = + _createWithDurationParams(totalTranches, defaults.BROKER_FEE()); + + uint256 beforeGas = gasleft(); + lockupTranched.createWithDurations(params); + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurations` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Calculate gas usage without broker fee. + params = _createWithDurationParams(totalTranches, ud(0)); + + beforeGas = gasleft(); + lockupTranched.createWithDurations(params); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurations` (", vm.toString(totalTranches), " tranches) (Broker fee not set) | ", gasUsed, " |" + ); + + _appendToFile(benchmarkResultsFile, contentToAppend); + + // Store the last 2 streams IDs for withdraw gas benchmark. + _streamIdsForWithdraw[0] = lockupTranched.nextStreamId() - 2; + _streamIdsForWithdraw[1] = lockupTranched.nextStreamId() - 1; + + // Create 2 more streams for withdraw gas benchmark. + _streamIdsForWithdraw[2] = lockupTranched.createWithDurations(params); + _streamIdsForWithdraw[3] = lockupTranched.createWithDurations(params); + } + + function gasCreateWithTimestamps(uint128 totalTranches) internal { + // Set the caller to the Sender for the next calls and change timestamp to before end time. + resetPrank({ msgSender: users.sender }); + + uint256 beforeGas = gasleft(); + lockupTranched.createWithTimestamps({ params: _createWithTimestampParams(totalTranches, defaults.BROKER_FEE()) }); + + string memory gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestamps` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + + beforeGas = gasleft(); + lockupTranched.createWithTimestamps({ params: _createWithTimestampParams(totalTranches, ud(0)) }); + gasUsed = vm.toString(beforeGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestamps` (", + vm.toString(totalTranches), + " tranches) (Broker fee not set) | ", + gasUsed, + " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function _createWithDurationParams( + uint128 totalTranches, + UD60x18 brokerFee + ) + private + view + returns (LockupTranched.CreateWithDurations memory) + { + LockupTranched.TrancheWithDuration[] memory tranches_ = new LockupTranched.TrancheWithDuration[](totalTranches); + + // Populate tranches + for (uint256 i = 0; i < totalTranches; ++i) { + tranches_[i] = ( + LockupTranched.TrancheWithDuration({ amount: AMOUNT_PER_TRANCHE, duration: defaults.CLIFF_DURATION() }) + ); + } + + uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; + + return LockupTranched.CreateWithDurations({ + sender: users.sender, + recipient: users.recipient, + totalAmount: _calculateTotalAmount(depositAmount, brokerFee), + asset: dai, + cancelable: true, + transferable: true, + tranches: tranches_, + broker: Broker({ account: users.broker, fee: brokerFee }) + }); + } + + function _createWithTimestampParams( + uint128 totalTranches, + UD60x18 brokerFee + ) + private + view + returns (LockupTranched.CreateWithTimestamps memory) + { + LockupTranched.Tranche[] memory tranches_ = new LockupTranched.Tranche[](totalTranches); + + // Populate tranches. + for (uint256 i = 0; i < totalTranches; ++i) { + tranches_[i] = ( + LockupTranched.Tranche({ + amount: AMOUNT_PER_TRANCHE, + timestamp: getBlockTimestamp() + uint40(defaults.CLIFF_DURATION() * (1 + i)) + }) + ); + } + + uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; + + return LockupTranched.CreateWithTimestamps({ + sender: users.sender, + recipient: users.recipient, + totalAmount: _calculateTotalAmount(depositAmount, brokerFee), + asset: dai, + cancelable: true, + transferable: true, + startTime: getBlockTimestamp(), + tranches: tranches_, + broker: Broker({ account: users.broker, fee: brokerFee }) + }); + } +} diff --git a/benchmark/results/SablierV2LockupDynamic.md b/benchmark/results/SablierV2LockupDynamic.md new file mode 100644 index 000000000..8d3ed5a05 --- /dev/null +++ b/benchmark/results/SablierV2LockupDynamic.md @@ -0,0 +1,31 @@ +# Benchmarks for LockupDynamic + +| Implementation | Gas Usage | +| ---------------------------------------------------------- | --------- | +| `burn` | 15704 | +| `cancel` | 71840 | +| `renounce` | 41020 | +| `createWithDurations` (2 segments) (Broker fee set) | 199085 | +| `createWithDurations` (2 segments) (Broker fee not set) | 183577 | +| `createWithTimestamps` (2 segments) (Broker fee set) | 183277 | +| `createWithTimestamps` (2 segments) (Broker fee not set) | 178569 | +| `withdraw` (2 segments) (After End Time) (by Recipient) | 19077 | +| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27735 | +| `withdraw` (2 segments) (After End Time) (by Anyone) | 13973 | +| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27431 | +| `createWithDurations` (10 segments) (Broker fee set) | 390783 | +| `createWithDurations` (10 segments) (Broker fee not set) | 386082 | +| `createWithTimestamps` (10 segments) (Broker fee set) | 380798 | +| `createWithTimestamps` (10 segments) (Broker fee not set) | 376105 | +| `withdraw` (10 segments) (After End Time) (by Recipient) | 14264 | +| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32678 | +| `withdraw` (10 segments) (After End Time) (by Anyone) | 13980 | +| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32374 | +| `createWithDurations` (100 segments) (Broker fee set) | 2705160 | +| `createWithDurations` (100 segments) (Broker fee not set) | 2701423 | +| `createWithTimestamps` (100 segments) (Broker fee set) | 2606849 | +| `createWithTimestamps` (100 segments) (Broker fee not set) | 2603145 | +| `withdraw` (100 segments) (After End Time) (by Recipient) | 14264 | +| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88561 | +| `withdraw` (100 segments) (After End Time) (by Anyone) | 13960 | +| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88257 | diff --git a/benchmark/results/SablierV2LockupLinear.md b/benchmark/results/SablierV2LockupLinear.md new file mode 100644 index 000000000..d86e6749c --- /dev/null +++ b/benchmark/results/SablierV2LockupLinear.md @@ -0,0 +1,19 @@ +# Benchmarks for LockupLinear + +| Implementation | Gas Usage | +| ----------------------------------------------------------- | --------- | +| `burn` | 15695 | +| `cancel` | 54245 | +| `renounce` | 21373 | +| `createWithDurations` (Broker fee set) (cliff not set) | 127827 | +| `createWithDurations` (Broker fee not set) (cliff not set) | 112288 | +| `createWithDurations` (Broker fee set) (cliff set) | 136615 | +| `createWithDurations` (Broker fee not set) (cliff set) | 131874 | +| `createWithTimestamps` (Broker fee set) (cliff not set) | 113929 | +| `createWithTimestamps` (Broker fee not set) (cliff not set) | 109182 | +| `createWithTimestamps` (Broker fee set) (cliff set) | 136217 | +| `createWithTimestamps` (Broker fee not set) (cliff set) | 131472 | +| `withdraw` (After End Time) (by Recipient) | 29618 | +| `withdraw` (Before End Time) (by Recipient) | 19100 | +| `withdraw` (After End Time) (by Anyone) | 24514 | +| `withdraw` (Before End Time) (by Anyone) | 18796 | diff --git a/benchmark/results/SablierV2LockupTranched.md b/benchmark/results/SablierV2LockupTranched.md new file mode 100644 index 000000000..c26d41a4d --- /dev/null +++ b/benchmark/results/SablierV2LockupTranched.md @@ -0,0 +1,31 @@ +# Benchmarks for LockupTranched + +| Implementation | Gas Usage | +| ---------------------------------------------------------- | --------- | +| `burn` | 15739 | +| `cancel` | 61652 | +| `renounce` | 28759 | +| `createWithDurations` (2 tranches) (Broker fee set) | 198189 | +| `createWithDurations` (2 tranches) (Broker fee not set) | 182679 | +| `createWithTimestamps` (2 tranches) (Broker fee set) | 188124 | +| `createWithTimestamps` (2 tranches) (Broker fee not set) | 182715 | +| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20258 | +| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 15063 | +| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15155 | +| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14759 | +| `createWithDurations` (10 tranches) (Broker fee set) | 385386 | +| `createWithDurations` (10 tranches) (Broker fee not set) | 380684 | +| `createWithTimestamps` (10 tranches) (Broker fee set) | 393864 | +| `createWithTimestamps` (10 tranches) (Broker fee not set) | 388568 | +| `withdraw` (10 tranches) (After End Time) (by Recipient) | 18013 | +| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19946 | +| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17716 | +| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19642 | +| `createWithDurations` (100 tranches) (Broker fee set) | 2646777 | +| `createWithDurations` (100 tranches) (Broker fee not set) | 2642559 | +| `createWithTimestamps` (100 tranches) (Broker fee set) | 2713099 | +| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2709493 | +| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46904 | +| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 75039 | +| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46600 | +| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 74735 | diff --git a/foundry.toml b/foundry.toml index 14cc8ac18..1b992dd45 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,7 +7,8 @@ { access = "read", path = "./out" }, { access = "read", path = "./out-optimized"}, { access = "read", path = "package.json"}, - { access = "read-write", path = "./cache" }, + { access = "read-write", path = "./benchmark/results"}, + { access = "read-write", path = "./cache" } ] gas_reports = [ "SablierV2LockupDynamic", @@ -34,6 +35,10 @@ fail_on_revert = true runs = 20 +# Run only the code inside benchmark directory +[profile.benchmark] + test = "benchmark" + # Speed up compilation and tests during development [profile.lite] optimizer = false diff --git a/package.json b/package.json index 69ff109b1..c7d96d64c 100644 --- a/package.json +++ b/package.json @@ -59,13 +59,11 @@ }, "repository": "github.com/sablier-labs/v2-core", "scripts": { + "benchmark": "bun run build:optimized && FOUNDRY_PROFILE=benchmark forge test --mt testGas && bun run prettier:write", "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "build:smt": "FOUNDRY_PROFILE=smt forge build", "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", - "gas:report": "forge test --gas-report --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", - "gas:snapshot": "forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fuzz)?_RevertWhen_\\w{1,}?\"", - "gas:snapshot:optimized": "bun run build:optimized && FOUNDRY_PROFILE=test-optimized forge snapshot --mp \"./test/integration/**/*.sol\" --nmt \"test(Fork)?(Fuzz)?_RevertWhen_\\w{1,}?\"", "lint": "bun run lint:sol && bun run prettier:check", "lint:sol": "forge fmt --check && bun solhint \"{precompiles,script,src,test}/**/*.sol\"", "prepack": "bun install && bash ./shell/prepare-artifacts.sh", diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 506639361..0edaf7303 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -18,8 +18,8 @@ contract Precompiles { CONSTANTS //////////////////////////////////////////////////////////////////////////*/ - uint256 internal constant MAX_SEGMENT_COUNT = 500; - uint256 internal constant MAX_TRANCHE_COUNT = 500; + uint256 public constant MAX_SEGMENT_COUNT = 500; + uint256 public constant MAX_TRANCHE_COUNT = 500; /*////////////////////////////////////////////////////////////////////////// BYTECODES diff --git a/script/Base.s.sol b/script/Base.s.sol index 2e662194f..b3a7301f8 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -13,8 +13,8 @@ contract BaseScript is Script, Sphinx { using Strings for uint256; using stdJson for string; - /// @dev The Avalanche chain ID. - uint256 internal constant AVALANCHE_CHAIN_ID = 43_114; + /// @dev The default value for `maxSegmentCount` and `maxTrancheCount`. + uint256 internal constant DEFAULT_MAX_COUNT = 500; /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -37,6 +37,12 @@ contract BaseScript is Script, Sphinx { /// @dev Used to derive the broadcaster's address if $EOA is not defined. string internal mnemonic; + /// @dev Maximum segment count mapped by the chain Id. + mapping(uint256 chainId => uint256 count) internal segmentCountMap; + + /// @dev Maximum tranche count mapped by the chain Id. + mapping(uint256 chainId => uint256 count) internal trancheCountMap; + /// @dev The project name for the Sphinx plugin. string internal sphinxProjectName; @@ -58,13 +64,15 @@ contract BaseScript is Script, Sphinx { } sphinxProjectName = vm.envOr({ name: "SPHINX_PROJECT_NAME", defaultValue: TEST_SPHINX_PROJECT_NAME }); - // Avalanche has a lower block gas limit than most other chains. - if (block.chainid == AVALANCHE_CHAIN_ID) { - maxSegmentCount = 300; - maxTrancheCount = 298; - } else { - maxSegmentCount = 500; - maxTrancheCount = 500; + // Populate the segment and tranche count map. + populateSegmentAndTranchCountMap(); + + // If there is no maximum value set for a specific chain, set a default value. + if (segmentCountMap[block.chainid] == 0) { + maxSegmentCount = DEFAULT_MAX_COUNT; + } + if (trancheCountMap[block.chainid] == 0) { + maxTrancheCount = DEFAULT_MAX_COUNT; } } @@ -102,4 +110,51 @@ contract BaseScript is Script, Sphinx { console2.log("The CREATE2 salt is \"%s\"", create2Salt); return bytes32(abi.encodePacked(create2Salt)); } + + /// @dev Populates the segment & tranche count map. Values are auto updated by the `update-script-counts.sh` script. + function populateSegmentAndTranchCountMap() internal { + // Arbitrum chain ID + segmentCountMap[42_161] = 1170; + trancheCountMap[42_161] = 1210; + + // Avalanche chain ID. + segmentCountMap[43_114] = 530; + trancheCountMap[43_114] = 540; + + // Base chain ID. + segmentCountMap[8453] = 2200; + trancheCountMap[8453] = 2290; + + // Blast chain ID. + segmentCountMap[238] = 1100; + trancheCountMap[238] = 1130; + + // BSC chain ID. + segmentCountMap[56] = 4870; + trancheCountMap[56] = 5180; + + // Ethereum chain ID. + segmentCountMap[1] = 1100; + trancheCountMap[1] = 1130; + + // Gnosis chain ID. + segmentCountMap[100] = 610; + trancheCountMap[100] = 620; + + // Optimism chain ID. + segmentCountMap[10] = 1100; + trancheCountMap[10] = 1130; + + // Polygon chain ID. + segmentCountMap[137] = 1100; + trancheCountMap[137] = 1130; + + // Scroll chain ID. + segmentCountMap[534_352] = 340; + trancheCountMap[534_352] = 350; + + // Sepolia chain ID. + segmentCountMap[11_155_111] = 1100; + trancheCountMap[11_155_111] = 1130; + } } diff --git a/shell/update-script-counts.sh b/shell/update-script-counts.sh new file mode 100755 index 000000000..15dfbe0f9 --- /dev/null +++ b/shell/update-script-counts.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +# Pre-requisites for running this script: +# +# - bun (https://bun.sh) +# - foundry (https://getfoundry.sh) + +# Strict mode +set -euo pipefail + +# Path to the Solidity file +BASE_SCRIPT_FILE="script/Base.s.sol" + +# Compile the contracts with optimized profile +bun run build:optimized + +# Generalized function to update counts in the solidity file +update_counts() { + local test_name=$1 + local map_name=$2 + echo -e "\nRunning forge test for estimating $test_name..." + local output=$(FOUNDRY_PROFILE=benchmark forge t --mt "test_Estimate${test_name}" -vv) + echo -e "\nParsing output for $test_name..." + + # Define a table with headers + local table="Category,Chain ID,New Max Count" + + # Parse the output to extract counts and chain IDs + while IFS= read -r line; do + local count=$(echo $line | awk '{print $2}') + local chain_id=$(echo $line | awk '{print $8}') + local formatted_chain_id=$(format_chain_id $chain_id) + + # Add the data to the table + table+="\n$map_name,$formatted_chain_id,$count" + + # Update the map for each chain ID using sd + sd "$map_name\[$formatted_chain_id\] = [0-9_]+;" "$map_name[$formatted_chain_id] = $count;" $BASE_SCRIPT_FILE + done < <(echo "$output" | grep 'count:') + + # Print the table using the column command + echo -e $table | column -t -s ',' +} + +# Helper function to format chain IDs with underscores +format_chain_id() { + local id=$1 + [[ ${#id} -gt 4 ]] && echo $id | rev | sed 's/\(...\)/\1_/g' | rev | sed 's/^_//' || echo $id +} + +# Call the function with specific parameters for segments and tranches +update_counts "Segments" "segmentCountMap" +update_counts "Tranches" "trancheCountMap" + +# Reformat the code with Forge +forge fmt $BASE_SCRIPT_FILE + +printf "\n\nAll mappings updated." diff --git a/test/Base.t.sol b/test/Base.t.sol index edc907603..2bd58e9af 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -124,7 +124,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi /// deployer's nonce, which would in turn lead to different addresses (recall that the addresses /// for contracts deployed via `CREATE` are based on the caller-and-nonce-hash). function deployCoreConditionally() internal { - if (!isTestOptimizedProfile()) { + if (!isTestOptimizedProfile() && !isBenchmarkProfile()) { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 62e990ac0..27dca7c78 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -23,9 +23,9 @@ contract Defaults is Constants { uint40 public constant CLIFF_DURATION = 2500 seconds; uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - uint256 public constant MAX_SEGMENT_COUNT = 500; + uint256 public constant MAX_SEGMENT_COUNT = 10_000; uint40 public immutable MAX_SEGMENT_DURATION; - uint256 public constant MAX_TRANCHE_COUNT = 500; + uint256 public constant MAX_TRANCHE_COUNT = 10_000; uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; uint256 public SEGMENT_COUNT; uint40 public immutable START_TIME; diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 8272487e4..50b1037ee 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -25,7 +25,7 @@ contract Precompiles_Test is Base_Test { function test_DeployLockupDynamic() external onlyTestOptimizedProfile { address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, nftDescriptor)); address expectedLockupDynamic = - address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT())); + address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, precompiles.MAX_SEGMENT_COUNT())); bytes memory expectedLockupDynamicCode = adjustBytecode(expectedLockupDynamic.code, expectedLockupDynamic, actualLockupDynamic); assertEq(actualLockupDynamic.code, expectedLockupDynamicCode, "bytecodes mismatch"); @@ -42,7 +42,7 @@ contract Precompiles_Test is Base_Test { function test_DeployLockupTranched() external onlyTestOptimizedProfile { address actualLockupTranched = address(precompiles.deployLockupTranched(users.admin, nftDescriptor)); address expectedLockupTranched = - address(deployOptimizedLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT())); + address(deployOptimizedLockupTranched(users.admin, nftDescriptor, precompiles.MAX_TRANCHE_COUNT())); bytes memory expectedLockupTranchedCode = adjustBytecode(expectedLockupTranched.code, expectedLockupTranched, actualLockupTranched); assertEq(actualLockupTranched.code, expectedLockupTranchedCode, "bytecodes mismatch"); @@ -67,7 +67,7 @@ contract Precompiles_Test is Base_Test { ISablierV2LockupLinear expectedLockupLinear, ISablierV2LockupTranched expectedLockupTranched, ISablierV2NFTDescriptor expectedNFTDescriptor - ) = deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); + ) = deployOptimizedCore(users.admin, precompiles.MAX_SEGMENT_COUNT(), precompiles.MAX_TRANCHE_COUNT()); bytes memory expectedLockupDynamicCode = adjustBytecode( address(expectedLockupDynamic).code, address(expectedLockupDynamic), address(actualLockupDynamic) diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 9a5257388..0d7192fb1 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -67,6 +67,12 @@ abstract contract Utils is CommonBase, PRBMathUtils { } } + /// @dev Checks if the Foundry profile is "benchmark". + function isBenchmarkProfile() internal view returns (bool) { + string memory profile = vm.envOr({ name: "FOUNDRY_PROFILE", defaultValue: string("default") }); + return Strings.equal(profile, "benchmark"); + } + /// @dev Checks if the Foundry profile is "test-optimized". function isTestOptimizedProfile() internal view returns (bool) { string memory profile = vm.envOr({ name: "FOUNDRY_PROFILE", defaultValue: string("default") }); From 8d3ab20abd0c0570313a4b4af53315ac0e5398e2 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Wed, 15 May 2024 01:03:57 +0300 Subject: [PATCH 098/132] refactor: remove sphinx (#924) --- .env.example | 4 +-- bun.lockb | Bin 306637 -> 42760 bytes foundry.toml | 5 +-- package.json | 1 - remappings.txt | 1 - script/Base.s.sol | 25 +------------ script/DeployCore.s.sol | 29 +-------------- script/DeployCore2.s.sol | 33 +----------------- script/DeployDeterministicCore.s.sol | 29 +-------------- script/DeployDeterministicCore2.s.sol | 33 +----------------- script/DeployDeterministicLockupDynamic.s.sol | 25 +------------ script/DeployDeterministicLockupLinear.s.sol | 25 +------------ .../DeployDeterministicLockupTranched.s.sol | 25 +------------ script/DeployDeterministicNFTDescriptor.s.sol | 11 +----- script/DeployLockupDynamic.s.sol | 25 +------------ script/DeployLockupLinear.s.sol | 25 +------------ script/DeployLockupTranched.s.sol | 25 +------------ script/DeployNFTDescriptor.s.sol | 11 +----- slither.config.json | 1 - 19 files changed, 15 insertions(+), 318 deletions(-) diff --git a/.env.example b/.env.example index 5a6280118..9a1fd9318 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,4 @@ export EOA="YOUR_EOA_ADDRESS" export FOUNDRY_PROFILE="lite" export MNEMONIC="YOUR_MNEMONIC" export RPC_URL_MAINNET="YOUR_RPC_URL_MAINNET" -export SPHINX_API_KEY="YOUR_API_KEY" -export SPHINX_ORG_ID="YOUR_ORG_ID" -export SPHINX_PROJECT_NAME="YOUR_PROJECT_NAME" + diff --git a/bun.lockb b/bun.lockb index f93dd2750c48e4fea2a4a03170ad68f283de93e5..c76cd3c12495a2f5d982a754f3c197ea9b109322 100755 GIT binary patch delta 6649 zcmeHLd2m!k8h<@66X$Uxz!H)Wu5cvgnq(%)%#eh<5Fvyk0Xz}}K_-xdU=ni4u_zf2 zSkx88rf4-Rl+lVCBdo|u)K~Pa)E9~# z_j}*3zyA8`^Y!%Kj|^IW(Dtx1v8A@=3FqpTAMBx*Q$4YdUgNua^Z~7I{|yU&Kehag zd%t;PWt%2bqqcF*h?w{WrK#rtO$$IY1Gs48#z_AQOw;;6Y4Vp;n$}a*E{~549&}9$$|o$&U^uX`yk>bh z0^D_t3Tc(Uy1J^dNoz$E6k_$V#s0=6nzjjg81&-~Rhx-SimG9eYS!z}$$w2%ZB-2% z0Axldctq74NDdlAKqE&RfaKr^kea^=7(os|;x*vMBMMl#tVue07i}W@7lBlMe^7rG zh+m)^B;|h&L{))SkmPqGaGgT zJ$4f1Vu15ejs~$1NCB6^Dd|3bpUpe)J(yDUtC2DJQe0iq!6lbn@wwEWkOg4a5;dzj^;~C0N;hE19+@|pu7DW!qhVpYqeU6}F z=k;zci{YnWa3@wz2@G_8F5PRq3oRF#gYSIP=fJ|DvLTek7V}f-CVPq}WSGWTnI~kLY&5UJvxK*2n#Kk!v|?%Na(RuT&}Knn(q}TS@|didw|h+E zB`mls7WX*AQnr?cj;NT>EtNQy#BzXR`-* zyU#S^AuM$8^aT_O!hdh!t-<9 zo@E-b82cHpWE_oPD|te;X>@|SUUKKA`gl8-e`03jfl+-q5)+OBRN5kFKjpC}d3%m& zTnuuI@67QUSy&#_NIQ4=ytbxrzSNy-JO^?bNE_do;WaKoqvohSD#1)w71U>YDcoGs z7>(6HBZC2~@`XT|#LpDu@C4H|PC%p9>NIFZ>>xD|Ayk{a9$Kjwm~M;YdHKWmD3`-{ z6I3D0W&auju&Ad%lT*iD39XRVoXBzDMa7IBG`@$X1`PojDOg`V6p@p}D2J9I9qi2X z8jnFsgN88Q_VI*#)98==f$~)kPvq_3?gv-!lZRu_sJYU@7(K-De$Mo=xxD>4(|80N zwNOqj;}A584fYvc)`wS3GL3qyI^xu{>VQTQ+|JLry!JTkHPiU^tZaK7-pcs)%xv}! zZ=Y-$5!h9N^CZX1Zr}+8rm+(om6dhb&p^xPDFxZa+@ZZ|*aXcDD;qzD7{26HQ%oZn zn}K9R-85RUke66)n5NxDcEQAsv_AhNL zDM-DM_;|@Gq;l6n2ovx*mRWfD2}AIf0wDvZWUr27mm0Lk%$DirknGTOjr?aqNcT|v zL}1Wlx*Ade>PTu421v6(@*tG*Ae285La8_6^GaKo%rBx$q@VCcDCB4+u}D`#ssLjz z6CrkLtyHO3Amg8$kL0J%J0PR@uy3N8Y0z$kkcWj3N(&*R`-4~pq|_TJvc;0U63Jgx zkSC-rtO@G9k^I+MgNzs1)ViP{Ar)*2>V(v{D zNcMLICmCK;A|ykadt?xRPzuQBl}G{J8|436B=aklm73&={EgO?4B1*%&GbSoNr6y{ zfBkiJ#jiVL9{^#ooK52;6a>DoX|Lf{kSXXqwNBT|Hm6#CA=HTFm`P&oTgE_;* zryko(@pUY_iD{x>G%E#cRd7K;@fbXL1w-N` zS*u{5f)UqBa=C(o3gQwZxkf>k0%xKm*C{xrz>_4&4GK;w$W4~yW(C~}3Q{DwRlx-X z#ZF1KDdqr7?Cc?y_kY1>Fh?e3IO%;DUnU@sey)(4(LvOOiVjgl0=^fr8x% z!g3^8p0tLGjgiVoTg@U~bh7?M&79hU%*i0N9 zLquAl%@Glb)q=lR0ooAj8p@lRs>&N)=`2dLJ;Yc;=O;zDr@9{&}`NtTQmr zwuO<8En?^$HdiMeW(2*K^<#AnwBm8ZYt+QrA8jUm+IlXlL_D1aXhV-81ZaPL% z-qIk_$DR%alxQoVJo-vahES@85J#ttdI;Im>4JRW->f`1n3TB;LWXo8S`HzOP8Y<{ zhnP+fRDhfiH>(j3q^R39acQ6)D^`Z+qXrsa&`oq5LN^Xte_^-l@y+O^%09Pts9l zHH3PNdI`N!AiH4^l!XvFz~XO>mJUgUBtgbO;vlgQI$6{Chq{$|g}TcRnJ9+$*OQvF z@JeT2>Kq!#IgnY9>mfHl=rnp0qzF&XD=>w7ivP@+CAWdIb6N5K8? zE!u~%Q3nRF3}>2?Tv14rv-%GoOl7|Hc@9UkxSXgLu}PvRNsncV#Ihtk$)KJ@hXe}5 zlS%qyV?I-tVAbMWlAa!8T^@CXjjtUPF@36yEpVlwf;9Z?GL!Xa_JFuKS+8W9#B0fV zI%^f*5p)Q@Q;!z;Df&?Mf|#FzN}EJSiXI(f-GENK)tnO2(Q+34C|(TtgMv-dhlF6f zROuM&GIcK7a-`t2phlU4E(bosa(00#mRwn0Jbq1h0!f zr6F|dn)Tb8MwYz#%9=hhGWf^D6o+BJR*A33&bo%JUl;$_e(m_nG73cM(vFCcF4Sw? z$NHwd-R*7}y3&R@;dZ*<$R}!C@L=78hDV=qW}?Xqu*Vhly9+dQ_%$<-6x!9Rtmbrz)i<*-6%A z?>)1O(JQyE=s*rlEo=fRO59h*r(`(VpGkUAhD2zTP3lSeMB)2_wp$ z*;F>u#wcWjf@`QZ$kAJ3_9Tqndt!11V72%P^N$@8+es@Fmoi{-qe#uvqcg2L;~hu$ zoQ`cw9vTb{15z2OzBt>)1(K82mX{4?xf3#+7vj!LjHPw0oPB@mQFrW*uc4^h zi9m3XEe^nUjCId^p?34#gZs3NfdLv#aSCx62JC5Zmj{q4(mn8JT|0mI=ljFEx9*ifW9!8k*xN4Ig~O-2`(~|0zas%f(ObIN ecS(?_Ytux_0ey^k^?)ATdFFtAb`%|VAN@Bfew54r literal 306637 zcmeFa2UJu^^FBN(CIk~Gm=&{vC@LySQV=6X6te>iFiLU=0w&BkN6cAQ#f)(kbIv(o zT(hF0YYzWxD%=ad^PTgZvwe1WrmO3zs;&;V@4eubFJ~Pdsd(fl@{RB+JM-(#vEwZY zwNK2quX~W+@P77j2Bf7@WzUfUsyq_>#28VJ{se1W3aV5w^iky{>`!P$7#bYluMG-Q zh3GV4VOovucs7;FkmO-%uK*3{B#8P`G6eY&LLbz6jsjg5R_5-y++CVZu zkkW9H?|b&{}mznKasEq;ZPFN*O+knVNU259F}6|F?AODrwPHoDeC(O z>A#rl)ETsYqDFERvyFtXyMnL~;WR?T*PR9m{Gmc#l^W^mPkCQWR7wJ0kQ{LoAw<4D z6R!keKT^hccPB)=eaR^5t%ST!s8y6YFhHf&`Gu%;p&G4UP_T{$+%F*53mpj#^2YG1 z`s>soAyF#T6Eco?CzCOZ$3KLKPaEW~(P_g%wL!iCT0j4=MAAb%i^RChAVgh9lLdT# zLiD#PB@O*GA}mFy(dmM9R+`At#U%YNq=)w1REPdrLd35rF4^(+R|oW^_>!oOIQ-S2 zR=xphzZ+CX9{x1{nozq1wRb1`7>D}g99W$Y`8`62ILC|l|Kuk|^h+HS7ND!6Qt^D| zc{{(1N=2?>x{@Bb!a7sybm}Oe59PBB#STBzt(18E)jA)4b(m^^$WK_PRS+!))!&t* zd_)D2B9%o{NB?FLA}>B#Uth>aQyqDr@kCWMNVKcHgLR+=QXTp0A+WVTdx2#MF%A`~ zsZaVV?@(ra)5~fq@w1GOc zZ|Z#gY%SSIJ5TG?lKl1!Q1^#}KB2)u*l>A#tC0Qtdj518iY!8-I%6a8bn5agph2}#M9S5%k=DGad+RHLU_ z$_v&}d0T1TnG?cJU@*-%YImzA@z)W;F3oMESGAPt824C0Qg zfiw<<3E@W*>aC`kr|}NZhSRXAy4y+oTEZT$Biz3!UkH#w;GdWQB z^Y#z!tMyUqd_y%6nxL>yoks2Bqt%6Ma1#9>M8375Rw-LpfU}gR@ex@rsg8KP zbZT!5$ic>vUfw1WzZ)U)st$^x>#?`L0rd}dKZ)@Q`Jc+obk z4)Rg4y@})x*O!X!Qrsm8p>HBE#H+85FRdk7yeR<`Ya_K!6_|(g@{ztR#Q_ZTshgr# zxUE$G(OS~?3awk8!dH2zLp4^BD%Bg3=O_K0?IhelXh?Oh0Cist#d(j~(Z5TC#)PdY zPOKx2cYOz`{+1AaM-oDBsgO@21b>7WA5BodaIH?G<9Xn%wW3R2u!`rUS8${zh~jJA zNwUZLp9|HI4?9A{7b)W4cC}BSRkSul)rI8n$8kCfy|B;#EiT9by6|4uIbL{5^LS$y z$)0yGtqYAxb%*4L|AN4Sgc#R5T_xN>b@X!`A@Wd$?BhDPv4=`kgK!8TZIv-?2x}6S z7WFsXRVpj0ClJyw#!MirP1se`D~tNaZYq^E$+MB&(u4`+RjRUtc7${(j9Eem`6qG; zze7bkpXV0&s8mHs&ihOkYOg}|JA}}8puHaX!F9kVG(c5?avdSAx79E>cc%SEepZ9ZXiW_+-Pl!C230$p{;`IoX;-YmN+@E|uqdMkGQ^Ep- z_Jrua4I%8z?=Q`>kA!G9iIC)e!P52YaJa-bBsq9=|6-+4d;8l7J#%62F>OjF)SgWG z$lCxy)L`r6Qx z9W>jB92>lkLCHoVpj(+|i$79~7AR_f0lLfBb0UTWv-^gWUzjxH0VI9ZRb5-_Xk@7-VP6Xvh- z(fF#v1HwYR1A>F#&|;$GuP7np(hk!GYE*%ATJW~=4e|;|F{|)Z^=Yy+PmF2a!_N9C622ouUcz*BY{Aro(ftaIIiF{Fe^qNjQ|?3g zI&gZbG!EMdkq4jPFuHG7spvSZfuaHV!MxlvLz+j+1WqJ`eh6VH!p?-)9~=Z$B1HZR z5Mms^OqcTefDrPxw7+0}J((lr#WPmwM|hZTeZ+s3>c|&ge-DfHwAVH62Vc*)KO0CN z@hu|6c+QwF*&j)WaSYRGG+N&%RU2wY|C|Xif9n#$uQn(Yw|Oe}g;ISkA@p7lV&2{+ zgg&2RLTIl>(P{dHYv_KR?;kcUmiTO^AB_phlEqRSvk5Vd69v-vYpi^{RMAv7A-Og* zltNVp22veD=tORa$qn&aFap z!6CHY2YdCQ^Bl<$AMZa+sBTF0`a+&EuH^4FtyjozZI}AhKUn93XD1g$-B-+Sb)+^J zUvuu1<^|7}L|XS)mvr|@_Z=Elf6_6d`Zls#j4*-POB3?`rP?Fy7tjBe_WL;k+Y(}* z=l!g&kjD{X-ZT{T0)(bizbbGaA^gP=<|jyPu%V*KcFV#@ubO_8v2FwF>k~=u?Yz|PyTrWcCdXDipcUGE*cwRs| zq^jsS$=)uKV}7k9#JJBUEI>Gd5c496FlC+x>-^NTLw30!*>NX?TtknjwYt!-wD;vM zLhmZY0XyF=N_qRqi=-#Zw9iJUQ>KHe%Vm+5s1S{nHdK}Oid1h+a`ZbiWmly0h^S-V zN56c@3ic^YnA#8Z0>Vx%LhN@wlzd%qlq%(6X1FeZ$EO~(8&Z4HHA(NGKtAsT(t-;1 z2~|}hJ>;=CA>w#{Nz7AmfAx&&kY6Q4KTnDAJwbKMBel1;CWP+nYu=Ll(P2RyK#$6J zzVY~adHbfs?-i;^d0w`a?3fdu_B$>5h5ekEs(|2dJZ@4Iye--H(a<9kO}~JgRL6L{ zPn5=w=DRkS^!m}f#CV$CmEtxK_~wojFYhP)Xg*{9+KzVq@@C2fOPeX(RoBXypX`vU zS=(a$lVT@XmF>0Z#=v2Ti^DRj_x;SD^lR&o$?ozgzTh*|y;~OPD`y{%@NZ`JHaHaIS0|bEJFqaigj_ zc#W->KWC3_C5~>3to!}h^)Z#cJ9Hb9x7e|%c@sx&TwA31!%oK2Dm-|7Xi&)ftEVm| z&)#^Y_`q_>d0P(L`EEtMjr;CL*e__{eyRJz&MzW54JctcZ^Og8OZK+7;^b7xEM)Sg zSNm=aUs>w;ls0ka`@g(etZr=LjBV{kJ*s(p@U)OEdG1BD@C`NV+D)Cb(ZA%6zdK*J z{?4OJr+o>74f~C%9D7uCcaL%T(S}Cvlf&}YI{(kkLv?!AZ*d~YW?u0~ThnX(8?;+h zdP4Vz*O$x_yla1W)_p^^)wvHB54rlULopZim3tR*4ZPQ`m1U(Z%PN(#F%2@ZslDW* zrrm>fLtOIi_*~`9?N^~@uebLuJi6lgY0)E$`%P+6{K15eyT7h2 zG%Ne~cAl72yo z$;a;%n)}Sm{LUr6A}cHpJimYLQqIRSZG+~lH;UfqJi@)v5|4x-bH3hl?%Hept=%um zg<2N(uiI;-wdKp1(KpK!JmqZ_)o|R>TQ=oB?N5CAXw0n|Gv~Yynl;SSaAo-x@jvd~ z?ta%JbZoQlTUS&Vn9#5C%@;#jm_AuOuE3QmxkAo97+SMc(eBq=4|;o_uKZRv{g(eO zW6zr>CN0_Q@omsqk3Y@7M{T2XwDySIetX;60^aRcEPnCPE3ubJo;qvGc`p4t@<)Z| zMrDiT8&=WgO8y2xg^RRo{wF^rS}u6IJ26j}3ER6A{^x$O7td#&w<8=cm1uG9m|O9r z%~R{wa?lM=e!en~rE{%(f7hH|yu*)014dtMo~`~Er=v4<-T{f#=Z#zzym`(nH^W60 zV=SwW)Od~XwDm1?>~_zo)?Fu7inniY^2o0Dt(`VFA2E9S;B$$DLE4smi&#$^8}lSG z;?l%cV~Zyry^+_}v$eI+VT-HnX1B8__qXZeHjf+^U;i-KXV>C?-sHA7zB6ulqne%r zK0GuT68HDu$y-j9$zR;U^}hY#zvn;LRm|QnyKU|$!>Bj$*KRugJ@`{0P2cZzPRI6c z?w!wKtjCSq2F(ZUnAGTGiKJG|&s8jaa>yxP$2>N99Cju48C-g6znQgcg64nGR_Hk4 zuL@P-_7|(Ozi`8Ud$pQ&a#q0@=h{8iyZ-ZHSMhyiznvfPBYxo*^CCe>YpUG~E?MhN z35y(y+AXg0uzC~Ih?0ZnMP2vKzi#*$udTe^E7rbUcv0sSrr({NkM^pw@@bDjYwC6x zY-I7*$LN56C$;Rw^Y!q_XYqr3wd$94o*th#Fuz&$%aOyYM1EM-b&yBPgR3vszZ-Fz z$9GAo_bnFg8`gsTRjIY&Y>6k~ABJz#oUPWN&CbX=-3P~PuQ+T{m*=sORjlS6-{7#z zr(>hCpNuWyi#RQQ-8yz}y$6O9)+bIlGBux3ZmWAG4!j%DH`|;34zD!(0;bfcGihVv zzv~BttUgxvQ0rZf0&CZ+vS!V;n#*%uZJ8}>Y2BFZRykG_ID0TT&)6op?<`wtpLg}? zCow%k;t;fX|6{3R+b_sr8?cBg^ahrJ^@&4F7Q5!I-cJ25}iyfai-}~CV+)eAAm3x+Z zynO4S%kftyH{(2Kk2c;m&Z1y=zmjW*$R z4Hw+IF(UVa+Aak)t_quYZk*4AZJo5Y7A7qmwY$mcZ~0g5Grg8;*TKhS?BDL&bfREg ze*;gOj;C|2Ib6-U+1HQVOp`x`e;VQOd|LdH!8aQ;8Kmp9{jW+-CZ0cV%I)8~5oI2A zEo~g$?EODCi$^W!U)1qv*VhM6zRcIL&a;xG1JCQPS6gIv?RaJk&r{AL z=a2K5HjhI)S2tT3-@`ZlR*p5h%MW$;T2m(B_)*KpTf6kTTJ7N)lhQBuUf9y~tjCYC zF{dX*R=XNq_0`jJ<#zPn+GP2Ru{zJ-w{M0IRvQ!=>QrH9P&T*t!e?Xq+WU|DJld{@ zw$a!L4+b2V=hOdNPoIKM{Ojzp%e&wh+q1m7?~I3_Y*bsH&YEaJVLjWr0!`l;xdP$Cruv@ zy6Dp6vO1aL9sJ~avvx-#ie9y=W;ytj!yMZK2_^Ai+i5Z+A62-!-ArEBEZf?faH@IND{6ef3k%U)oHHdD))h>=pc|=H@lG zdpBK_xMr!@?vGttn>01+m#5@%pI(EOwhHc``L@=sRD&V^PQSSPpIRMW=Bz%ec8AHm z%{Jz_lJia-x8eTNKR2)qj|e`R=kBe);sPSwIxKe7jJj7U(RI*thvl}~gj0qK+vQ(3 zZ&{TU-b-sdEf~MpyK~(GyVvJ%-FtZDvxL5vf=~2zHSQSq&ziPolk5sF%GY#ug?WFg zNA~*X(Z5eB*00|0z_=zAMvcRs;FnHT-s&1EwV)yjjhyZc!JP-`KZd!z*uJ-n_LZ zsfqe(k+6g%uDXt8R(duZcI0Z)nbo_U=;bqNTl3Wif{M;Hi@sE~ykVn5hZF5gwtkxU zH0tp1!&Mu-S#@HQTh2q@4jgySW3lfR4HN5C~Y5;e9rOi z55Jebop;s6`MbZ`9hey~b<>eYZ$^K=IqsZ)z;H9;e?MRDxT)dbaa*R%C~Z3Lwbjj0 zg9FVPMUENrJSa=C!^mpXXozfygE&+WPAPd!zB z_@kxY9NQh=;Xga}#RmH&rtuzCN|pRJWa^s7$5j?jM~>fnZdShQ?`C>#%h%7bXL7{n zCX3d+-ackZY@Ubpm*$_dGkoH1C-X%EVkfTdXmh#bzFQr(9$Fq8JL1Xm();f1j(pbc zTGMZiuZ_(5_+R+ky2zx+a^J6?zP&is(6-FZ39n2qO=z-r<;j;hJo=A&G^^zMeD@nZ zYdL+Y@iX=Moc3WWFRL27i&*M5en8H`VLKMjYdUw$WzRK7#%~-obos%;Hw-2=GIg%o zIQ+obn-`z;zxJSbn+@ib9+$g4Wp4RqhwO{G>)bn+H{H8n(be-WLYxM!-8ZCR{?*Bm zqdjBGZ6C0#O$+tf0A(O*iJd z5g0jg+eO{?wV$utpHR`ZRdn?li(b`mjcPo1_kLI7>t?fS6pr!z$9&|m*u9>AJ-F4m z{<=w4I};1GI@PI>uFBZJxqp|Ns@{8`di$M=+E$8gZd~+Z*Vhy74zl^Nt(1Gtak~l_ zEWF>#resV{_q!dQwyWa&(&wM2@5c;iRkG>Oh$q*wm&xxm>sg5b9XxLg-)~;@%$q^y zY+qz^KUt*3iPfVET+8W}_&Vlf+iI0Q&2>5awSnWwe&goO?LVna!oqU?)e65~mr%J- zz6ie|m+yS9esXrJkzW^D6%4HM`E{*RRR=D+e5}gb%@?dIs>3bX_R}qB_G0U@?$1^^ z@pXD}g*6rOAOF_vv*R)MekDgAWj&+HC(U~-T2l6eXZd`^ymPv*iM>#u(%vm?%~pg3 zY8svUws!oIQNxTs_$>EWz9#l$S8vs@y{nHk)g5`-e8s(;onzehw$~oa{{7;V&UR~i zO)Qjc_J$rV<@3#+|LkzJ)~C;2uR8j0bC(HKqW4c8;Sv75eHoXJo!ie>eSh`&#FY0d z7Vj#RV_2bLhi99gtAAyAwcF#vn^$dN=X>v3Z2X8O1-q5&JF;H47kr-O{q@@O=V#_6 zHkr!Tfw(=rUJi0yv|_U1t$N0Rk=6q?b)Pn5z~!XFi}#eRo_w+4$nM8_4{c@mZ0o#) ztG6C4n;YnEYcwph^_a>}Po5rb(t4cpg*yl5cUu`%s`#R(Yj>9|?P2tEq^3)>+rqfp z0iSz&thoMc%!OW2M#gZ4jY3|-*jgjNgSyvWlM~k*KUVy>q+k|JxxrTj;b`0ufItf_LO_Bdet=Tb&dPM*E8K&N&n? zJMA&INLp&D#l-z`Fx$$XYHXvDz{BF114^)uxsw~t3|6#T=KE% zmZ;vlS~PR;=@jj^U3+1CnNtH>zX+O@`_rw3w%%vx21lBNB2G3 zJi3^@wJ)&8I@|QwJx{9N9X!1J&9@^ff=cW)wtx9<@Byp!FT8pUHJ^U{hP(fR!c~Va zt~)hu>sh10OGBQ_uVwTx)F}JrYr1YLH}bx2yz1lgdmoE6ZV**$``t4Ojzm5jeCXwm z?Tac|++V(LrTqw9yjpu9m;cS7(Ro{WhOhA{*u?AX+Tsf~t$fkg*7&SfT%G%&YjQ?> z)NC8QWQS|;n3b=;^j}neWN@cZqvy?;{wR1+ZI4~rONVL=njGuqpIl;%b({Xx7S%n! z;k#+%;1U%U-<^LZPGhsoYVWv$hvLp2{5JcWy=nVawj<*fk4vt%Acw2>ewWo_UevBo z-Lu1wwmF=QOFK1-nb^k0_v;yh+f6GxTAVw0P?s*HdcT`qGQ{Jo=i|=0ArYNzN=+Q- ze&RxC!uQMV8|6Kj=V_%D?k7%Nac{cn`Q&?bR?J%XB4^p&&is6#>E``8hs}*wSI)M) zX>`0pa@)ZHf8W})W!%$YdX>K?^Ded9C&(h+Uu11&9pShIj&}-1+OjI znvDLm`e60R^HgybGY`hNl`VNAK5zd5CQdq|1e0dBOMi(7sc@`z(HUKgLPv+4O1nR# z-52;=_25Q$>!wxal^f&!)nM!Xl16FI&wn~MyEQBDEVog9^8=m+o9B_;$eSc@L6XyyyLEZ=p$l*(?mac6vb3 zI*)s_NuFZ8XF}^H-z#)i{Z-)8r^!QkKfC4=_R_S_mArB8Z>+9bbb8aV((3}AZO@#Y ze<;MwO*ejUV5?H!KU9r=kh|i|Rx=vbn)aii<-@g6o^^SDEO)D<+9-F=@O6=gMwvCU zwlkg=ZMtakl{q6S4>MfZ_@JHty_@awfKC0)|nssKl^^^HZ6I?*t31+Zrzg5s#2Ar+xWV`*XOsP zPiJk=Je?7n=i<7H59ioa z(z&J+;x)~!%d0z`UD2cZ*Vf5H)kE_(UAt|S=ONn~+5a8CYTY@vx9*9%D;pNwx?=j% zovl`^UbQ$lsd7PEejdT+{q^+p~u`(7Jxdc>l8l?o(8d)7|s=$p%>Z|v2p%MW&5m%o^{Rh766Pojg* zPG0ry(z(4au0#b_u6%B=;qF@Z?-gvE$FaVvW~o;Wvu*_^M~$A)ANaqU+lxOBn0H+?Q0pD?D=y`(yEO>4{y?e(?P zl#gSay}GO#y7AHE`tt@_=6rbY!#&&6PwZB$fATHYlX9n88yao$EkEk&%K}5Qf7w@f z^x@vY3wHYz^FEnvXSL&wH%{#xGjHqG)%T+d)LZ{ur0zbiWbtIVfarwLaafyY9JY zKsP(pw>v~_vg7-!620F}9nr05+r%c$w-VcZ{>$>j`&6^q@}mI zN{(K|-d-xO&c4vqX~pLqiYXc!bhz1_i2h}FR2mT2;IrL@jt0Sz*9sT2-TUau?slse zc=CQ?n0xGDx4k_bve7$)tQ2~OmQps*PrQ!_(RtBtx`z4JvaM6Afu^o%2g&jNE=B1# zKe7uMy-rd!BfXrW&hp<-ei5-=1?q?`@eQaIHdy|P@^31vcc1w6iH~|7@%fGV|A?4h zoW3+7J``B?Kgz!mux=;%Vnh5~qyztQ$A$TE^acLGM^VauEBKs$rF`ogDwPxYNB$8L zRb>_EqD&=1C*sTHNvzadKPI9B@sT?vh5c8gz>z=1ucRk=ek@QtiOZ!h#&ry z;zEf@~{~WvAImGM`RU_e&*SrrbQT|EI*)pZ`kz*P~z7!1~Lq|6tiqd5Nw0zV>xu6y`i~sa z@21Eq%>P7u-v1%P9xkUazb&IGX8RHF#j#_oro`Y--T}!=GV?I?H`%t_b0wn7W{7~eq-Vz9(94;Kivpn{qz1yCS(=l3Z)P6U5JnI zm)m#nn7^L*SbtbIkkN3;D$KW~i(X^m^S&uJ2IfZ+AMwl08wbbyzlmQ{@G%GE+F||& z;$#2h^`kWYx`n0l7yN>&ls}UAokjfUo6`7i5x*JnasEG- z--wg>Zv-D)xpPOKUycr}h@XA4UFf7&SkHs_JbthtcMO@okoZl>Ki4^q^n9a@^^=M3 zl7;wfi~c(Pa&yT3g9M-BR@(oS#K-=_{EYg|?d<;_;v@gy^B%@J=^^t=(=YeJKjt6! zO5-0%eE64}H;#$@ClDXkU#uUNu}*r(x_0K$^%wnzOl};^A3=OC@{f9E*6$9x&gJ_%6i9{!gL&vwjkb z2N6Fj^Jg{jZN&It>^ZKq@usb_-dExyf0%!K4NR;1yE^lo=#Nz}{z}#!>@h!*_-%>L z<1RM_<{u+IpI;zjJHLxrU&j1gC8hBLk8Z_f?;*@@Mtq(>upu`O%pXB~Kk7f`4{c@m zTN7D@`Ok^(B=RrUHykkEh5qOge9Rpsh4~|h-!Jy{)5YQ;Um4mdJ)9O`oZ|IEIl5#vF1K+uy2|YD<9@NBTylypCcQDai2$65pEmxNh<@fL|2oWCHWTM5~vpwQGr1bX{xyj1viitz6hsq5CM zXIs0bYIRxZ@09*zkp1r?JzL=)xv!K-?`S1y|H0VPqYTB*|FTt9sL`5Ai#Q{v-ET!*UAq3s#rz zpWqv@vpgdktk;$JmgGM-5pZ@@8vk12WBp}z{@x^hUE;$x9R(H7-!c?DuK(x{`mc2S zx)UGgC!(elrTj_6Zz=fTDxH7#iI4LmoMQ}>`Y&lk|7L;UBZu@jMONYQA547gKOkZ6 zRqB5i@p=CMm+it{dWH2q5+Cyiy6C^s{iA&im8v=M;Tvm5>GfkC@vVh_qT|>ht8n}m ziI4H)ysJ^2Esob z!a}#AAQ}WEPJ9A@MnXpt3w8GptvJHg6XZ zKV(X;U*5#W{KLMHnf}ivKJFiozd{)Wt=G=+Un4%okH-!3SWaQSDINYe|JXxVo{NKSif9PtM{im>jx2^reF-ueU|@; z$8y$NEch6EC58DHh~HGtzg!#4uSplL#>CI8e;x68{;*9sF|h6t;?opPd47i+$}PRQvN!)~iC3ANyBk^Y24^?Ek#~{@LTN zE$n|G@tuipO3jeTjf44jh>!6rDEPm6`E!l=Hgx#W&!5~g6!X1^--7(3j`5Q_hRk0_ ze5@a?^Em!Fa;b&&lZj6$$n^TJMuUg_gRfgk^RFR3#-I5a#m(&;{~{t|{$c(=rZj&y ziI4S%am!5p%h1DncjEK@snmZU@!N{{xo>ii`+to1yno5{4g1V5M9Bl6&kk~JFux7) z=@$0q{FS>0GJgQ^G5$PnmHLkt@nhb}ahRQ_mlAW7p@mBR=*I%pLe=yU(n-5+B!J_yZR?kW-kSi(a166v%Y`-HDI<$&H(1WB)UVkM)PRkprds zN48cfRaZU#a^qnC-H4Cp2h3ySIRAvq|BLw8|Cq=4Cmze0|A6?se!x{ae~Qt|XMH}~ z&j{In8{*^of&I@YBa&V_^M?_?J@L_m_~q^a%&$eschbwB((&&{e7^o52BrSj3O@6c zj^9J#^Z5r{?iXT7udtp)8|n8iP{$Z3egD{*_~<{|V@%IC+E{O{;G_R?`>xNwM0{Mo zz{N-D{4GT{|IFu@U_Yb6y4{G6{KGf;pmhFB*7Faa7y~(l{hua2=N~b!JR=*dm%E+x z{DS?$hMdCudc^1X2VPz|WYS@NU*fxn{IN`q3D!NT#|MwsQAReHpN}>VT)(*AO8IWY z=lu^h*^XTQgNW};{yG0jub+E~kNYoPKin_5{y!0)_b;q{rT%MoNd5b3xxNt_>+T{x zy@E)|KXRuuf8UAE@87{y8h_o6QvSf@nCNSUg>^%SuOGkC_5T;~okjn#cPZ`vGvf35 zM@&lj6+EQ#54f0vO8MQ1umAi&>H3*Ve5@bNCxsxZu>Ls_Km5uadpKZzo=&OfU-X^j z&`Gbbo+t6qe_ns-arE1mKa2SM{KS+LSgx=8yYH-bp7>cA|9qXL{g1~@>G-=5---H< zxdR&<*Y9H1m$BYx;&cCt2pjr(fBMe+1H`XK{-K8$3gU~5!u(IfcP2j8E&8ss|8}0z z`e(k<^&hIoFD)Z(R^j-+5g+Gg#GOAA@z?Aktv}es`0+eIJ-x#IeTh%EfGPQdzS8{d zB0jFaymr}cdcM)ddhdx}hxm|T{8^5AdWH3>b(Q8H#w|1X*JP2unE3PxCMAEF@t>4M zzEwAA{baWPKE!X3h4>c`pZ<%%SY>AY-R?pEui-54+x4XX$7&Y%Cy3ua3w-BZS@XY( z`2Dirzj|-_e*k8IzmoWavcNB|&YJ&)#LtTV5?=KGw$DQRQ;1JT(4Wtbu?NX1y#G8P zK3#%h_`XRg-_={Cq9f4H{Z}b}F7XjRU$>O zPyW$=jKAE%e2>0T{F&v?C4Q4E_)jE$^DOWy1!RpMOnm1o_}@tUmRaC`$zuF2fvM;B z%#8mw;%8<2J`o@DKeO|vZBW+c??mGB`6Dy^&mNq*e`JQgi1_;JkJoWV>yX#qE#kMy zLjGJsq`$w+Z2qSaU;q6h?}KvVKS6vqz4(>(zYyI#*bpE7$uNE_ zhfaEh^&*Im^nO)%8B@>zNL9pI7;^X|obw;`T55#XQ{38aX z{03oJd;dR#_&EQ;x7=$#`o?kYBtD+sfN!QJhfaEh`Em5{0M{?@@hOlVNw1Chxg&q= zKg;!0fBTj7S`(k=KNRKWfcfKzUsJ>nKKdZ1Fn>4k8w);Ua`zzSepv$w{L-I4O7rKKhOab#QN(Yi7r#>ee&XZ)kM}>N{m(ZzYyEd6zW)BF)c(76F zjwN^e&JrKzckaJ&MnuuhaheX1{{Jbw@3K52GpyGq4WI4EmT=B>Hc9pEH(eI!Et5O4c7A_KAsO8JH(RVpXqbH5qo#@~YYSU>C+;~=MSyi)-7(@hiQ4lpgi#_;Ein z>I28$mH7JO$8x#+^~9%NLHW6VD2?A>bn5;E-%7{NllU%r`OleA;G&)TIiL8resNuC z{+CnLwAo&CQcK93*E-`B?ZxQj4Kd%2tKdqegZxg=;@iBklUuphpPL$41%wtUJFKwOu z`x2kef6(D^Osk)^&isYMx1spiuTuUw;=Aba)B5>So&B3mQmLGXk2=;q%m2h3=No zEs2kD&kX-C@#_#D@uTl@ZE*bAr=-q*C4FFied6=;6V4%pkzrxJj`)~AsLLHY7-#+t z!G~`ph55OrO6M1zKT7l0p7=E>e)i3Fxc(<(|HFu1m-x8;;TojW|0CjK{$T%Bk^}Z% zc$&2TppH2xw=my@_zlT_TCSHSOkIOIX7!+aqs!|qK2K|x`9lOB{YLIso>o6?o%MF< z@mZEu_jh&H{g?QyD1P`iq>s}4J5QI!uOM-e1G!_s{v(KAkNl(W6*A#Jj`+C$=lr!K z8*&Q!e=sBU{D~Np@*B>~8h<+R+h!$x;`8}CGx0mmO1=Ne41abO`7epj_m7$J?>sy8 z{wFj1>BQ&xpBerg;%6oP+H<7qH|DH4eU#q+z9YUf%^&bFr_17tjKcHZD^@!HV*OzK zr`^Z?WQzGWiI4psxl>Y@pKq>8p^+xrO-)1s^>0U9Ju0-ypsn#n0h()57qPPc7Q}~t zC1a=0A3=N@5%Uqi$%_t_V0 zGyf&=aehPHQ%??^^a}HjEKa?C@ES^w$8F4iPkblQf4O@%Y%t$;iNr@;?%7qJA3=QF zf512RO6T8F;x`rf!~B(7IQ}QZ=j&Hy#;?Ls>G}_Q@LyhL0PJ5)e2hQ1bRRCeFntFSoJo7vkgmg4hdlqYPxe z-EwLEa^6^;kqOp|CO-B*=;x;oj|1xI73RkiKP&lvNql~OfIe_P(({cr_Frm+bp3=3 zT)AgR=64{zgUCN@$SusDO8f?bkNhc({{->5|F9`{4`ctIiBIb;W&RitpXC|#gY}xM zl)SFux=5UG(w~8*&Qs=MbOQ ze`fN3j`)qqKYU{DD_uW@|B~iE=Z)inz4Qv}H6=dQFLaI4Bcy3#{t)8V68XyveRA%vY_IuKz#l`cBgM z&id}ecgjNlClMd>7xM@4%k2aEKO+2dJ)Mw$X=43c>r&T06qNdRB7S3vpJP|bA4Yua zU)c9Jre6a6Lxpws55q$KY*C2h(uyFkKHcI;!>Y3s9CqClm z{AcJ`D6s!6g3t3u>HhJG_?<-l<@$ym`*+ z`ByGi-+z%Usn5S4ms{9>7vk&ZUv3P{pG5(CFSg!ncT zKk6)#69?;VB7O_v^V*Xe1M|O#{$uY$Q96HXZl1&#K-t$_WH4c`1_3tC*gw#3&Y>I|%rCZGiXU~@P@2Ea#OLwH7|6{7`=3pGzWyS9rRR?~#K-eD z%$q`)@Nc;zb^ju|?85Q;5TEyd^q=J!8DhPK#IH;7vp(lPRO214(}qR09UE6_W8ccr z+|J1Si^NC%!GnLL`7_y>`uu`@vyb$U{dXol`Y(6f*(UR+62F<~f00bYf1UWY#8;Ag z#K8Uw?2`N={=D>2y8m=0ek=0Nxl{W5>kjcd3w}uiCbMw-H+M_>7yM%VuskC(tY^L_ zYyWz zFCo5u{A5B_Vg9py((iv@--3Uo`@iFU>HZNs@Z}cvA58rElz;ZGl)sAjSii7`5A4V( z?EgLSn-U*+NBk_$$Oh{*Iv~A2guYQmB)xX#&mn$0@(7#W2|3rMmkNF21O8Jfl zrRx{wE%H29!{9fcA zeW!DP>>RNFbHsNLe9S$3&_ScmH38j=071m?%&}bbC~7ONw2V8$)i&I znf2eE_)W<__^`=#)ANls*4svWd*Wm4%~+TbS&y$e_UrwZTobHkLwwvnp)PmsAw1>> z5})rsA!9jo(krZYkoX>=|2Y&40`tv}OMI>?-9HBrzZv<*{E^E=zu4bl;h*;nxi*+z z<%D$qm0AA*#7F#yiLW8}o>5`{g-+7nSP(xK5i&FW4#amPKK4GgnUQa_v+f|`WB-7R z*ATvERG7bo_&9&?)M2??{(ItM|A#*EC%3SlI;T?4Kj5-FBRi}YKzx4w2pP-e@)r{y z`C}gEK`#Fe@p1jY`~#Qgv0Q$|(<+q{@!79ZzJ~a`|CnaN|6<}dApe-ZCiIazhMceK z!hdG@re~!1Gs|y7{CZi4e-!bv(*FeFWBq0}{_n)c^IPnDa>t%jf6nt}XQk)&@Sh(I zG7FF24dV0lhv%>y6U?_bm-_pc;2FswlMeH{5Z{UV&+}g<{U<+`_#KIl*ijgz+Mj>2 z|ChvXOMK*>Wq)R+wy>`K`PB1EYHP;dm_MBO?&KeJ&f^~}uwMB?-HD>L~ka`D&mAI`vX3diq8d`l6(93Ja1 zKa}{$AJ>(R{|4e?{$Ty%Be$?W<4e-{2X&UovBA0?#OLwL%>FT*_}IU}HBk@)`}esl z-GB4gvpl0du-**fBYw_1qg?(4;v;_WkpIFN5k))uH@zbHhd49yzdiAth5rIFeM61? zPbYpY;zK4kcIYzy5b>Raf5?>P&){n6_+@7P)*-%)h#&hO$3zCa-$l$n_*NSK2IAX_@dsaS z46OH%_&7guzZo;?1M{tKs8mjZ&$5iTXlLDE;^Y3A{mNa#%->G@I>d)fxm@Tn|G8fL zkjp&-F~9mv>H5iBT!-Wo=0_19=YRCyls+ua$Oh}}Abw-PhYil7T>fX`^Zdcu#U3W7 zuz$N-()t4j`B%FBBZv?GnD^i+jei~Sv410;%d7^avfef)L z&0jO(*CzkqqZmt&;ZM&00OGe4e7W~dFwXoVB7V$Ue3a(D)a}&y1Flkj2jc6GpVIwr zB=H+l|G7Vm6iT{<^^OuB*Dvn7()s&?_zuM9ekma<3uWf6IH)`(vV} z>>pL|MP`9Nd{Fce_c0|?q`xBer*ibc7+Z*TAm&^}QP)SvIUXQ*RRvZfMA1j&pay-Q zXH6fJ^bmSA=>w#DfRyq(L_5t<73|YqpQ2w+)Eg3_q=(?s98KvbT`N=OxicXO5bcdo zp`wpCPqwBH+UXuQrRZaJlF+l8l#(8T-%jWOu}67|x;{d$i;$;>(CaGn^bzuILavV( z_ulkDyP7^IK-9eidK04PBl@RFk^YLX*GI^K7?&VX*GJe77IGl$^%HdxcN64QEIS{-TqOOnFgZ>qAAb9UZ zJw3#H`Xcnd5@HX{4zfUe#k)oL%_-zSe9a{=w~+r1(UeED12L{fq7KAYV^Iepp2DIo z2cc?0KM-FL!P7^a%d3(ceyv2i9K=3RN9d=ASU2@Z4`?U!f%w``)PeZgNT9ut>mx)C z^aK5H67Bj3d1E05;%gIuE&^R4r1CpNQ&Z6n%tLi|Q3v8{8&TIsh}sG{5MSGgIuKvm z3+y1Uqd*TdQUN0V&Z4f55P1qY5P9q-u&0m%@wJzz>mx+Hg-9r5laaEJb?=cp|_Y2>vts~^wtXbdP3-L6!k5H^q*?0z<5INb`wHx4;s@TM0@E6 zFhSrxLaeJpgy0=PV;V$U$Aw%Up?^}y^%3*(BFTX_388XJ=;q`AjB6fBqHtQOLg$8j?IWNdL!(b5LQj3%^B#eIVi~ zPDrj*B?vKoysSz8VIx#dO-Bgg%Ez53po&e+X#6_ zA=gLv?Ll(H-&?c;;YTgxKBBG>=u1fdsr=~&`2B=jM+pD@3F$vol&B9T#CjVk>f;E( zn@))MVnzF6Lik-mhyny}wWtFT=UPJOtrKz}>T!gyw?)*q3XCU20YYz^r~_+I{U1Wa z{ZzC+6YW6gKNsz|DF*3zl!#60>2X??rih}yzHn5#CYeTI{5iSyOBU+ zf%yr^gsPyZ7a~Lf!k?Ltn~QpBLf9)$NdKuS39Ks65<)6Ke6^+@h@-Zs+Y-WGeIai| zhysM3lRy_C2SVOV)Pd+{bAc^{90++!LfCIjh^Dsm1N@GJX!j6uPa*Fv>b*pJZ&CLa z=qpewFn|#2C5#Y$A_$SEfrQA*P(qa7A^Z=ccHnTKr;iYg5^^B)MiXK_PZ9O00;dt8 z{0_mJPVI(;pf^v*^%3#~qJ5EQ*GH_Mm7;yMX#X9;?_Z+*cZhv% zt7!kf#G+*P1lh&7oF&A#T@`+S=-+iw2cmwH5cB1ZsNWOqKz#j&exN@O1wIn;r)Z?2 z1Tn73#Dl;0gz*1S*hvp@t~CNlAmTBmI`{>I{C5bwf}%Y=L%oLfbdgB z)PZO(E9yYh%L%j~L{laD0lQUE`2)gkbc5DdIuZF@N5cV61 zdU^;wd(wkFN5OL`Mqt z*NOH}Laf(Fp_d+_e*=Ub5cRg12;t`gnlR?;)x)H-DpA- zeMG*7ksQ1cq8$j{XhMi4i27tg*quU%>)LEW@L~y3GJ~Kl6nr4;FA{Yi>Wf7ki24#j z#J60?fsn5tEJJum$n_C%9uaaN@^OL?^Y^NdX9eN^8rgxL8^WF(L>})6{of(%-luk~ zqa>jRgrC=<4uswtQP)SvlZ6~ukm}iK@xgCiEJA_MGZb|o>iGm33AsKZe+5a7I0}n) zAjYMLr~{#gg6j!BDEj!{`+#5H4{P#W}hVp=UF;wK^cZhX1QnV|< z|K0~k?*)+G^xgv?wP?py`rrEiWaHQO1-PEnK@u}STp#{>A0Vyg4wNsXtfN4@2S5Sh zx~l&k0CLo!^56RaWJ7vC@ZbA@|K11azgPJ0eZYV31O9s-Al-NU_dYG!zLlw$u{?_6`#f3EqHrz*Erb=nzpzIa$yb#rB-ksY4w_*kj!hk2S= zO?&Nr`L9dNr$t+9yS49hX+}XkyEr>=F<7?6SY4y7LpHnF4=$Sjv#gS2L_9^_Ib91uy9MX17kNCa|`{qn)Ss|yxlt#nu`BZ-JXyZK1o$1=P zHtxNuJsZ^1=%VlW;CK2szgVMO4C=iy9k@C3NAFtr&q#-ad}>>IlI$kOT1ghfAs9)-60 z?0BKA*L%w$?b}5+>YUH~{)yrX&8s}w(th3o(KHm$2B$gRCqqFQYh9Lj~m`Kb1^tub>-vd zdpA}u+^y`l)mIiy>~XN@$HrBUw}`O3=0CGW$pZCUcHB$~TVK3?k39W0Tqx#Hb<+Nt zc>}uK-_h=gU7?<{rQflZ)*GI=a51P=<=W}P6YCq7-k0s^*(SAC3=KYzfAeIk)+Gi8 zMvvR_d{Pm^$>$yNKEL{A)b=OyZ(DRYUBF;>SYqv-h5P2c++IBbzkAB@;+-cKgVp;c z3@%#dfm@MM4)v;^b3I`=C$Pz3pCxC8Z{B^oZwJpA-IC`|PW*c3?t~r>EfWjQu&Y(1 z?6=;2_5bcYa$bvS&kohqvx|4WTnzknw>sE8uJwSZNy|#s|1qiY)ftz&O{{*U&W-0| zw=S>S;`^S7VTRT6cOSd?wfWqdZ!NDoK8^|PWiV&cqEbnm}=Z);=Ru4I>6qe2Swi?+Sht;dY)3&WOP+F9#k%#)E9 z9~ND(?Pg9V%P~EDW)#Nn_Oo3)Obo zzUtoEj&m#b%ISKiu5YZJameE%`R-25Kl{Wt_ks7`mc4VtE$@kZc%w&wbvKJGzjW?<>$BT;#~6GL`D?73p54N1l+a*PiTG)= z^M9~->0PkJ-c=W)%d|K>wPwSx>Bk4TwMokE-{`=T=nlokG#imzd-CO^s_rLxH>#|C z5;gMR#>rM~cg)`}{jGsCfAJ2Qi$T)n87HkiH0eJ7!-=++YF4Uo%j{|!*OxYBx_ZQ` zZ#3%K!)tuUg{3Pm9PNB`;D_?<7Od!pYN+zecrBB*Sj>l-QmYUb-Q&&LFcO^yfV?Vi+g`A26fIlI$r(utHfP;cFou*p}~;oDep(vytj`TVU|$la^nx(^UYb@IB%P~Mo&-F$(8F- ziJA>Jwyb7vU+Roo?_1wOyd1t1(;8WnHC`Rp>2$qpbq3zkvumzzx9~u-Q9DDrAGeQL zyYt(peveN6=redgb{Fl8zxm&1%XydE6}a5> zO0BKDwba2^XB%2o+xH$VG+^dqlU<#LTRiCC zXm$SNn0)37V=ujYWzwbk(1_OS4>?$NJW{H=$Hc>DxAZ(Ya+^o7$4-@gnE7=Jo;)?U zg`V9~`teqK+u>exOznEzt^X?iv_b#zTF=O~ce|fkUv9{zdZlA)bqo*dx_9j5#CPpa z)cJp;-DOx+&l@*-x=T{JTe`a&0qI6Mq>)fMq>=7U>6Y&9?vRvjP(bSZeE!Ghn)CY1 zo3&qkuJ1K#@3q#c?O%g&s(B)VLL^#x zYWDbko2OBOZ+F@~Vxv^~bmkY+xf+XCXxZ|U#r4R~8i`wXPP6 zY_-#82SF5eW+|9~^pQJg4GZIhos~TB`%Cr@{qG1f>NXINm%k2S(AO{;7gm^u&r*#} z_7NdLT-~3>(b&h=U*t8f-9&?X-x{plr|z;|ANU$1cp_(6eT&EHVK{UFATK%SZbNuw zRtR|S<7i5R9uo3;*8kz$-HnK)VX2>U+dVmKZG5#nGdz5%p2g@nOlF2&JvhVc5tXv2 zxnYmOG_l1A-Y+OXclC{*%!q%?`ceyCn2jsFHnaMA!+l=YRo9f44C{P?AT)6c5k&fr z(&AsOlX2?8JF#YWBM~X~F zxf&$&4_&-~OAWgDPunqqb_O|oH~6W|X~Smh4i~e~_;k-l!pYW~7NqDTrrO_2Hhd0z zBck-CjEDz$ieeEgzB|dt{lX11SIEf(TpG|-L3bsDjShOp*62(zZlBJ#CsK$C8Moue zz$X+2+s;sK-t@jK@QYz)rU=Vv%Iuy}gJtWIltWg9`@w#=e}2I5i&19J31_b2y)nmuL@{*#|UDZDL#fxwd%) z>k_@&W8G=KI4M< ziQ#v|4*tj$Gw1+GlgXieYsjyzd6xkK>fQ+WLFJtS?r=|$G=4=jZvdA8bZ>}qYx~^1 ze%W%R+?|gkysOPlX%}vck30_MzYYIP&>4K_}@(Fk5V)|C(H=3O|_r- z$;~A29Q-~of^P6y;U(8Mx{i@Y$uA#tahF9uC8}ID8A=pPoWe1Ow3>{wd`gOm9DidU zwZjjk@??&X@1)0a8-7ls(95FapZWLQs(=0a26R(-#q9NdLKqlqo>`SKj^Ae}Kt>`^ zRjw9{y*J74{T+ro#dMS&E0x_WxTwzPyam}^N+$DZlUEnYXQD{@`ScUuGJ)=nVn~0T zezHT^xaV@S4x>q^ZUZ4EjT)AI=@nr{Tk}vzr%??`%~TP>z;S@O!16I>MgHrWKjhhv zP8ro3NEhJs_wTzr{~Am_Yrqk_${$26K4cb;oEwv_s|(H;T-Mpi$g452ajonyk(fVA z&Dp3~#q(nsc%)WM4jxkz23TEfh&iA74Tchkm{d+YP7&+08?g~bJz=XcG5Y0S=Q^HsLe}y-yz~CI=Hh?P zeXO9Xl{(+6*2ND$wAP$uBNQ}XnR9yk?JKr=ppdx`ZQZC!WzcUze`GyzVM_B$2#jG} zmgBRc(XFpJwbA^9vu|wwzH|8Rys?4qbcNKm;q6nb4qpjkCTf3&xZ59?crn|TDwCky zeF;;^OJRHCO>2f&^K6cj3pvKo1ZA^jD{M^R*Wn`HAZ?nb|V zA@Xbr)`W2m`sv{*dn>~V=#;O`lUg}On*c87|5g7xZ$sReezS}=W%~oxyVA_ZJ7(6zR^ zACBjT?YzrL)yeFIU#c#)n9+JmB&lF{j^$w`&A_T=jZ2&-k1Oeq<~V&n+)jJ0^5s)3 z76oaiylKQ@J|f_9gYKka66F~zTFb>J7W}jyFwwE=G}i2k*%8ZUNdex^p_N8@+<%na zw>Whh?grzf+WEI8lBxoId!C@jVRm@f#_<97?|u;f8q9>~?9cbG+t_irvg|%+cG!_F zmmiTH>@}a*=kwUrSaWpyk4Iq$6$X%UnvfGkNzpazpK!DXos@%VS2b+8y}|Dp??3dv zBMjNON(UE;9@dmNA^%KZ<)Ub8?E5@R&V+dG#nqW<}-5yL7^JNmaIxD{c_uBgKEM9S?3 z+DqSfm-X1W^~p#U{C9U;{8o2!+HX~v*&tEaMv+SammhTVab#jX`eG#iMws8%!&cBM z$vMdgK$L--5|AV?`RzPUH+QWT?yam!?^E^CR25IJ3DN1}ZT5A{GmWz{vNRN&HxdBd zt?!>;Z`{(pO(~{!Xr(I)Ek0YM=Y~f7_g_Yz0*8qzTv7`;UnEd)q~1Gsds|I(6k_hI z+j==#rCQwB7g2s7l>_qrU5ERx!F+CS-(`>1?Dtv`HtT(t-?#}4{cDM2AU}CLo(8iQ@2$gY=5iBKq2w- z=Vx>*jkFYxlJhZ~nOhnmWb11n@85k%{xz7p`xqmMZOFi}PnsmFKBH7{EW87_3qob2 zNv{N`8Xf%N)zgbM{5Pbps-XEfh+yER`3AY>Nllk~J}JgRO}@AQuINAXzaz}{>go3* zEkX_5_cqgE&3sr;1`9u!-418?)QFkLkdI7=7v6YmjG%Y@R)lEaom0vCdWbgH&eXLC zSF<*AI=zVoxMHCD*6{SgB*iMRJo_yZHot%GWJ0OUBecx4nx4a31ZPXOs+k^fd~D>k z*hosxjHXf^{a^!?mx#g6&5#f7i6`u5fGZBVJsCQ6vsV2{VXr8p$rG+nq*ICvVCl(( zu}O7l-ejc|EA}X=1XgTq3CYvI!jU8#339x1woYL_V3cMzhnugG1Y8Nwy*}40*;~cq z*SgvD(W(5px=>CLN+LP7MlglIwW3Jm#^jB86(+R|%jx>Gu5ftSPr>-5@hM7)G6@#6vWjzi5wPly*TLZv5Z!IZJ7|AXr_<7Il{0eJnD2Hk{(Fu&*qiNsf; z_(YE4A#b6ht=-iJ+;lM2vCN}Ta73A{V?XkOJ%-!CfBwnxYuWcW}2^(aEbm-xgG}UkYIQHaXAmR4EckKW7Tp|a$hK>mB=p-D6 zP=|%cgXPTPZ*Xe8P9hfF^@!%zbTt*yCA#e$8XigIC50 z!hTcnzdc0$=gNcbkDx4-Q!F;a)}VFK)bA&Zk!dALr(el`I$%qf9mz};w%^evZ`F%h zdqZRserzO;tW2=hgCP)sq9!Lt{PKlQ1n36^(2ai>u=Wu#(QMQcj6}Mb;&US*^E~1$ zvnoKCmh}+~El1h%0)eX3c{~vcf^r>C2 zERqFx5D%gC$fvuflE43)F1ZFdRP&eQ$p*KcZ(3=_*}Ew{ADoQQOC1^CI|}%p>`)Q> zqmyVg0aSqd7Ib+}=}E2S4=czm9EoktWEY1uSR zgUS2}A@c{G#4dWndrk)<4ofCVaugpdYz;)xW$_q`a3yoYp|^E_s|>oa1E25hRmOYV zMbwxc#wS!?4v2J9i6XtwPNWa_K1rIwNCzB!^Rp-5m0|J^zx#G?po7toqnd)!nPDFF zBWDw=JN?@i>MsxD$DV#!q=>rt@;$Nq=DDLx+?xZDIJsO=t8XX6^tL!rZnkKh9gz@D zb?zd>h`;9zo{+zu?zo1~V$(GBHAhz`koO&!_XAmYhr?kIc@4kxD_Kgx6|xKG4H3++ z8BB<{ep`vN+m=WVvT7XmwlMhI-`yP?CO-HvgjL0Q3YH$Zte>Ag&WwC;h0B0Z8}54NDOe_WUW&UD zRHjOD6I3L`5w+I_Z`twjnoVwX$p5z|$NzqB>Y#f%EyHb-g+tD?9Ak^rR9s%N zzn)nVy}$ljF7yxyw>SC)r8Cb_)W}6jpg1P4wsf|-V5c`^9FM6)Z?;r^>Tw(B2My4j z6yjGH{g}@Wt>4|z+}Lo;6QDT1Mi)42meLkP(7#P9&isKF!9k_I@(9jAFOOLXoz42| z7~yXG9udu05qHW2;A(>IXm$k?O5#-tkIztHc4fDE^)C^FzQ8c!pE&I)1{|u#qm?iA zv0B2oJX1RcgSlpp&!|jR)*WKx+wMP)PHKIN&k@UZ%p0Gv8U+_8ET-40^EQ5ll|pk zjK6W&d?ihiyi{5YK#l8bUwgm&+h|hnkt2xS%C@BJS2S8NPdM9>EzikaO>^+$OkPo( z<;L=F)i@Eyd<%i+0>IS)^GeOA`)I+e_j52%GKeEXwJLoPK3D%3pfuf>VtXgU6UJ|o zg4jU2mcyv_tC5XA39=#PcMK)JT-)X*O=XS4Bt78%+Yjyk#dWsB=&Z4Tr=S6 zfqBKbOuOfY8lwbRL;Z@W?{dY<{oe)^L)O)q9>&=dhz0MY?@4OQ;BL|ObMfCb_3ETn zkc@`hCqW&@5EB?lqT~avKIm5G87=OUh!Wh%4zq|mN^lAoZE+oH;z-*pR?cj=UN*Z= z>8xT|H?_?y-fLt%t(YcuhO|JYjN6}yIXzvt^!;y-q5u6Z3_!QN-m08L>K$xVV#Q~* zKHpNfFO)P5#kLn{bry)}DGUwkauRR{Q91}_uRh(s(j@#E7%e`@krIN`i z_*BOE(A%<>ZSY>lx*XjX1N~qGx?&gD-#4morkHTxp)Sa3P1cQ!ZB>gA!k7C3k6F7f z*4K)pGlBludE>P_T^KXI3y!s_wD2fII4rb5ea$gtE?a&Rx%)KRYFe^O(wBS_v%sgs;6Qrga14H38lBz1LshI?&Z28Trn?h+R4it_)Xb@ZnE8pn>ZXzJnRQ(SiNI%x*F z_^3fT1S(pS2X`ofCS^wE@f%z?sV36fAC=AaTFjp@8at*3VK0l8Lbi_z6Yoc$3FPPK zW7x2q4;oX6YVeK0c^Grh73ngC>OVJUNhIS!Sk#t5gk(7n#yW1mj);@Po)0Zv=g^6>mHC)%y&r1e9X+htsBr53|Ea%Of^JU9 zYLI>``DgX!lgCgjnjz_?%%(fCUG^3{kzN)v)6NC;TUN4j4d}`?;qzB9XU|jie`M>G zJl_Z*C2$^VH>Ci1tw6Ul#;+aUyLR;}$!&P8&tPWHyN>6N3wZ>Ngg&nzhVx2FuN zP**j~x3eX zo6Bzbjr=;3k8d%hK7c=86UR*aDNvHgk?Yv62sw+wjLPrdX^F#wd9Nr0Kf;HgAI*Zs|L!8?`E*QTfo{iUBu>dZR4E$Z#fo^|84{5Tv zv69+FBTO)1?uoP4h3lE#=W9(0rNe7lSy;y2(ef_fS>K3I7gg(NP8vs2n=ti`tysII1El3l$Svn0Vz z#$dN0#dt{T^Fmh$NGmbxVNJXyydVYo*8y~guVeAW(ft~!c64ibnpe9LLjaTR(`x(0zwkOdn%Ag)QJ{2Ya;BVKvM%!HyrXigYoiA1dX9km|NA45*9pL2 zR#@7SdPbF-yD&ujZdg*8Szf0ld{dbTW{BMV-0LQ8H~E8-CGUGzwXnjlkRk-rk72DX zQt^ATubM~~os@piBUXN&O*2GBUU+~G#-roiL1+0sF1l_U@Csc%(dK!Jj zF2^W-mI^2AUD2|gg_VI05ngFi46+&qa0Nqdj(EpAw-IYtx)No!4mVVLa^%dAe&^}2JJ$+a` zBN|!+nH;UzQj^>EVC73dDT7|582Gb!wClAuI!BiK;FOm+-}#i$W) zVC#fYTcVcD23*g7=zm9;{b7r~0>4cxXBLqVqJEBqE&4!ZDXsmg!+4S(S0=&mP80B~ zmi<;35_=HUsf06oCBLjVdy$G(WsSL{k2aT10M`q2U3Lpcr1kTrTkA829!FowBo7z-)K^UP6ZV-i6L~rS#{vKL0shOw z?Dw^c@&`|Qxt&I$%WoLbzOIT2^VqO}>b@BB&TgH@U{Gx^^sPOnhjV}9Jkdqfgk2|A zq;|jI=5+l-)nhXRteg6Pd7b&#I|C~?DM(6R9ecBIiJ2cDVDPJ&{IMjh7+d`hjle zYxU6puVmWVaHj`oKG(uUk2MoxGv8AYTN0kW{qJx;`J(-%-DWS?%@+Sa3GaLzK_C9m z;aP46<>!uz+?&k`xc;C!()XB#XVP!dLW;UQZ{YWdAoZu^V&J=`A2!7%YTTI-+8P_VfX(D(y>M(8c%E#RdMd=T6vGA zt67&FF08@2bO`9$VPg7GP>R@zeE%LNWC|0Jg`s|`CuE=i4pIWje_?EB!DcJcdgofUdUpdUg(7jNf@hTc<^DqLRPnu6?UYxd&_3JdNV zhc}_W_)*^_PY1K_m=vVW-(>8d7oL^ACkY>eYnO{+=D&B;OYWL${kw}O(7juD zvkV`p#}cfq7L>kbnVs8%mPvgIA#rByHTIo`_S{_}UTSKE2($SjmJd%|&BVxeqkuWh zn+5ty=jLR+C)f|+pt}}fG~Tj>rivPsf8%yS%iU9gipXQ#J@f-sZc&&t9U5svhmUYJ zkqjDHHaPki4c5w<07~NXcmdkYcNR-M&;RXN@W1hV1n9QmDsL{kcpVy6!0g*q5|pH& z1SzlFxCsyw6!ZQLdJB&!{xgV@Mv=&JzO`Ja>w`37avyqHY~B0QPb&GmKJ|b1;QiMR zk)W&0u(4+=b+Lc4Fl*I^>YkvLx}3J^{td}~>sD(AV{hOO+LY<8_OXH9D;<&7ZBrOZ z`BsyanUfmj_H+oV7D3?sA_{cr;(zf{BHwPb`Cx?%qHqk`{8as^wQI&{5vS&^(r<`o zR(Z!&Cul^1TWuii9yqtFzpLUNy+Bw+$*zvSlFga~27>IzFVrOGk`^I8 z;jUW@QAgq^c<)567JEYpUso*d3mWJfSw34u6jW%39Q+7Nj53o)a3%Xc8rx1xS?TYe{2px`;0(;gIOU5OKZ@RvMnIGd}h4PMN90tEkSqp$I+U zSKdYGWyDwN90KeKUBZ&g=d0cX&$QV9 z24XyOp0DRda4o$jc~9&5<35|{B#h9zH$hH573&fmj7g=i(4pWwK^EwSGDZ`zy)Sot zApOus`Rw#fNMM}2dsgzW1t~W*LL;TOW#5PfX;(344>oZcGFg`Ex-~nWN0$UP+{s_> zST{Hn$eRtiPYmZ zCsza9JkZ52y@4dVgAoiz4mIBtgfHgb>)>b8E;8}g>9Y5cS%_pw_p3p;)tmYV{h0{$ zeUEiwr4Ppk<&=w86NK8WNHXAabw21aaf--V3fD=kP3bl3Do9>b(I! z)MbuaRRbfeub(LVknrSKlCppO&2|0ptis#3QVzG6B=xj=O;>terCoL5_54YGiC#ee z7K3h)V1r$#YVH1ou4=W=WZ`s(hH{2osAe!wW6|Jv_2-Q2*@`pId+0t(3|ptx_OV!!w?qy|8RAU|4S-t) zy0~kMgtwLO+(A(xvBd|}qc!!VcX@^Znpv0d%bC^*cv}8#`JF!W#GL83{3JwUfur8f zsJ6|z8=CpMbJDXZa)4V7y7}ptg1J-gpZCj{TU<2u%~VO5Uaziv`fOBm zLP>x4Q$Esn>AYJ>Q@viMgUbHoXQK2-nshH6T;6DJJIn zB)4z(WSo>>!ur=C+wmZye?zm0=6+k4<@IZ-jX0Z^8RF|6CZ@aU$;O@{&8{nuw-R)* z;(Cp~mwlU%4>#2Nl74q2Ldmyxz)&g2Zh`UxR{EpyW1p_Fjw?#_%1>U_vbadaS34$8 zZn8bQ4yIqmy8{uw0d5uO1~v~KJZBE^7SsGU{IdB#5L2NZ78V@8``iLGzHsXm`g!p| zB;$cprj&MQj0yq9mtUoE2%|nhvPv}w25J-myiQhw?&IQv@|)Sgg2rJ?CEHD$^BFr<%~VNJb;x~=E)zh0P~dH}Z`bhnlQ zZrtLrwqqgsbI}L}ctvw`GORvd6aC~fSGRv?e`R~BlSjMy>-9mY}#FtyH%%>>-e$Fp)&|s;nrrgSB=AbwiDEEy7mqJY)fO6 ze6|(ly7}b+;1rvxTAtgxbsnVP344;t*Y&VqP>!>|1TrNKOjtSfRM_ zEG|V`0ZvX6b;5|Z&;wjHExe@`l!CWk0Jj-*f0J_w!{o(J{~(LxraJeaptZzu_s>P@ zr}Yx3)~l2AfiALe?@Y%plui8khRC-h2E!<2rnQahNch{~RfvfX=(d0^fo%&eE;ZuU zGhR8JcQlvz=1?fUbX{^nx5ZTUEw+9iK2X*1&^8SW7|FWSv-Sv6v~BT0T4+iRW}r@c z2IuC3W^vm&PI2}1XgUEBwiphiSk3@NWhA@a zt`HFkJhmbJsis<}-L?X|9JGToc%5tmU38tQj;VpE4x`4q0bTJ!LZhPTT{gbo{_Px+ z%neD=cGYqkD0;Z+?V*UqJ-J70!4%?BK|Tm(H{>!wBZZSR;JBq7bZ3(L#}7zQO=PJ2 zXcX&}mjvOXra#p+9sFLc`##48g^7x|I`i;pfNUk&{VhZhL72=FauBq-Le=vrS^Dh& z8hAhM09`LzNy^UZY6qvvThrQR3l_VtY@FM~L=fyP6t8y3%7!>{syl^{9;Evu5?S}372Ql=dF14aou1K^_prIlTZGpc ziF&pCvmw{fKx+#FTWD*WZo`jMJdLy5nqq4#H0(ipw%83^uh9j%nAIVyG+B$Q(^ofe zo|$YE{Z{Er-j!%MxTnum9=jN4{I%O-+W2qU^@|B$aQ<*)Cr{wZ?iQv!2lrPA37ZXo zb?I)<u_K-c(PXtXs!N`3qwT2xKS0X*JJ&+yIgpkb{g@3&p< z`3V={J=Y?mC|?|dz6S%6`zZBYeghh~O<1OpjsA%0U*I^a7j(&L5U_siqNex%vUu_> z{$%akR0mT?XHLW`mPa1^oAgl`;xc#7ec)fN{LJ@)#eXy}Y@szy)4S%JU_}vUXFQ;j!vRIZ& zBX_h2YOtr24=<}Yg&jY#n`IBf`S4ULH);JSxkNG?a0ftFynQxrbhAm%%i~vR?Tt}+ zd5nH&(jTXElZ-a~iY6||zH4`a{trGWkwtHXyittxxJ(ti6yH=z7V%V4YrOXc=hp{8 zw>``~^yl*?MS|{$bi_PWFl~#^NOB2_6qbc<*aQ=&%5NSs3~QH2oYrv0AQ}|Mda5)3 z`81EYOyoi#I+-ehR3PsV=vHRV+(RQcySiBWtwtx1&A;ZvAqm@_IVthYK> zPWhB`8ILC6-mA>B6?oXRZ(^6&^blZZV{dXFU;wzopnIU>(p*1kW;eWCHLgxZ?ICMA zQE4>*d1XZ{H2meuVu#p3Tkbs6?=l?1T&Nl5>sWj-dsc5_%i z{sPA<|CrRedh-KtM?v?}<-7nwu$9i}`*B-A#MD5X&MD1nw?vBeH0jYY*lNOXspy9a z$h7u-L->L4`&9O_vJzGeg_kMZqwAFM8)s&~9RuAsFX@#^Y-G>2+BxYVSUH4!C)^MB zs41~d%d%E5c#!qkv@{+31oYey3gWFya0Hd5XZS_i>8O*B3MDy)(EVWjcpP-`o+L8G zqVwWoEtqH{Hml0%;3Z<6F(9Xz$mpBDM5Z;&^aQ%G`#!{P6>bb6W|CYDahn~QEcTEW zyQ?Z`PmO@{auc9?J~?S1o3?_*GgHovF(8gXM)8ze;4aw4?g12sGcUc@X^ zLAEXq&dg#2`h*Y>M{}Ljyn>-}mgA3o1vM+YcY+}9C;!dvCMMg~7r>nY-O%6ihkKL` z*!Dj*J)SJwF}o31V-<^$=!y)c9|TILW!In_#su;Lx;Hn4u5Ul9UpE9qua#MvJtDD#_TF+B`lNr$XINNhGM?=8 zQ;c9kuX{e7N^FDLN`>T+n8Zv!;JnR)?vr{?<$bfIxO5{+xArH~kWJAD)FH;x{OdYt z_H)$k$&H=y+7x3Rr`1`gJKJ;)d8HS)3 z{rzvoe|4Ni(5<#cAN*;`zU+6<|NG337yFgu8GSVJtRtmFW-Yr+=WWEVNt$5qh_zEQ?{@SQqf`IvtM?GqjwR7px0;7|oTBExPnI||80@v%Bn&Va1f9#F3m0M_L3ru zYZBTc1JC*faMwY%|4{V<`QS#;d#nb{VC~jIySt!;@#Nn8&bY)hafxjV19VU0OP<}| zzX_`Agi~F=TD&szPreMQ|5gR_Ve3#;9&mqvu3T+8#4_sf+xdvlK8t4|rk`@`KJ0|Z zgyR`>-vptv_Mf#cekmM&c5&WxnClSk>zmaJN7gVw+43BCCi(yX&b-+NtIt(NgI&1UAIQ z*7WY@_Qk@V+cDyEv&Py_>$b>CmUg`vw>M=Rlzfsmj4`%%)+{>UJnc59W~?;Dr~?qI(=WaK$1-u0yKzAHQdFo0}(`A(l=kyd&T0d)TsMVj_Y8)%emR7u=5c~kWc3+i>ZOH^LSXG2ZNr(Y|u z^hr;`s$xQjq$=}!A>?nE8(lzv zK0WNKgGySK^8X-*e@Lq^LAe1-1bahyES8TZs$g5x40XPV=); z&qAy9L{aZ!03j{ZqAF_$xc=b?bdw-22J|%+^2p|-OHP^)KKp5sb(`28tX2dL2`1@N z>J+_(;!gkc)+Fxxa&$24?9}vIV;Pv@iXQ{yMb(o(8cKkEI0oGxSCx9Q^B0+mT!QDm zbQw4#Hk|}B5Z0b_p$>k>&Ccf49IZOiLK|#NFNIg6TaB$B_*PwxKEN91k0P->qo#o4 z!V}Q_eSVTfR%YsWud@mx={1Pu-|(LLD92t((Uk&$8I!!_k3r8eY!u&cl_Uc z^E*`un-`a0D~1{i!{hFM?ImPjRrSKehH?Em)V}7_1#r(mH&{~Z@~viMtieSqG_7sS z3v5zr#dQGztP#cz!BR__n;2pz(y)bbgUbCjZwE5AJ=f%9DF zpxgTGWC;>GiNiSG>9u0Km{-`>pD+iH*}pIseYmv5qg#^bC8M6|BVsei(VmAM(8pw% zOKC%>GLOt4BMVSx+VX(B7of|%RkBF(-<=udeWDZ)D z2=r5aH2)D=iZ=V4n`cJ2rg5602`S|9qBaD^ny@I~UV^TJ-Q@S(Z^j?La%P2zeH2Z) zGHyjj;$LR?FtM-$aoRR==6*3t{X^?+MTs~1>kGG|W@Xj1YL`{^cML8QI)$j;fO`eH zq;WB5BhInYXA?8CfqVI{*YQ^hDIH~Qjob8(Fi&TcUdHZeSLgQ`yv$)9la`%{U2O)e zVqD-1ahL)t;(eVh0QVYnFZa?16pVkv={D$7|75kNaV*beg-+!M&#Z!7gDpuLYIX&xAmX7I1Gs_kGL?LXu<#eue|8yU(pC#}q5) zwxa-l-*#GLF+p>Nc2J2c11X~XCTU}#B0tsYhU|mZY=#uc0{e^3_N-PgGT{CK-EvGr z%9vy*o!W&&pJT%X_?ge^O36;;gG2_|%L~I1BzO~vu+!L$=1n))CTIxAE4wf2kMEU? zbD$*jg{RBs;sEzI=%(ko%6L6~L#jBSZO zoToMT{>Ie^W64@ahU?5Qo`?eJ2ot^@JjyDBqliCstDp2Le!Y9y=rafM-hnPB1$P|T z?l8%`hj`IyZRUr&7*dKbPZj$q9W}dfcceV~hZ$JUh0!5|vHoWr6z;yjgGdq9PvemZ zZ|U2*)knbV?>*?+$F$-{QlJL$b_e{pQxQzUHvIw-=>%CR4;fs{NA?6?CS@yxWE`t3 z8^@=vYL?l~*|Y2yd1RwKeEgY!B~TWeKl=l^nFuRq_M5V0Sv_CgefHr)nm6L*ba$?E z5BQ=o#kzd6entA4K5o<4qKqIsLRE~Q3srvK(}%xsPasxkRu-ZbJZ}%6+i{CmU5$9d ze_sI|9p7qY4krf{W4=_0csPYB-_0CSfUu*g?cCQ{iaqdQnvqDX zC_MN7{CD}kamyp=?UXUjV3?9c+c zbF5`}#Yas%IV^=c~`5)Zlu#XVBF%sqhp= zp4BiMpgT^Fg*--E4-9)zLb5VeBIww?S9Z0?M*o3GXaZMjBo@?(LREzl7?EwwcVY?e zx~cE4FIooVeF0tf6k=g3jOlE@IMv@=8pn^}n2`%o-dql1wxf^G+z|ViRr5?e_cT{iizRRSt~#W>tv9iizqkG zht%rNAVHj{Q32bAMWp_Ut1PQ^(d0MBeg>LaKjoH6PH$E+@_S!z-58$zhX9*>$&V45 zPNF?sl{^UB*Fat<&@CJEXg(W$Et}}VU>c#>#l-*SL0+?wyfFL%cjzHL#_LRx!lt~+ zRu31$T)u_7Vy%_&*53YhGgPL{QyO1V{Qz*GL09)dDg1y-UAOP|llbr&&7IDoyKnW4 zMV5xbo1gY9PZU?{QuQ;}&qtI}%e0n0WL7N9gi3`5u@7(Yxkz|5Y;6G-26RtkSDnpi z7VA`S&(PBlOIO0Q*+po(h7X+<#fIoqRaqIob$>#I%^)B75CPp}&X3FqWfG{EHzL65 zOCA+pt&_!v)oG3_ZnMo^4NjskYi(-y^p;L|vJCmU|; zHv#-V1lWC~#4}L@%a~t;qm}3@yv@KmIvnV#&ger3v%ku%h`g=S-D&S)rtOxSCw&p2 zu)D(eh`!a)>hwwC3F+y}3>M;BC)D~NL)2uth3G4RSDy^e#nw3=fxLffFaH{h(o&<} zNQ7(h79SiJ2hR&+$!K`7s}66NpX~3$^c0E3)tDBVF-vk}WL`Xm8TT({1$f)sxIuG= z&j}}wx1r~TfQtaS-}BRI#VU4$F?pfi*6dV;`JG3Kn`DH&3b65Hs*PR_noZT$gfkMT zd#GbvdEW8UPrxo&_8D0q$l`i@qOLa72V6wZbu9F%?+PkJ<_)Uaj&C|!6;C@YvNdRbG* z8Sl$|HUr$h_vU{Mrg!pgP(7HCN4WmnQxPU2sxppgeM2&!q5iwRmT}FdpWDJKu3u&5 z$uXtBqt>TW{ob=Yen6!tqK%iQEr8r>k^@{6&}D@gc1`oDZV60&ZezNkv3=p7yPD!M z^e0b42xuk3<`kA59eE@&M1{^7#SG6QW`7xShbxrIV2F8!_o+At1^X8jbU7O|e0P;N zh?p>i7C&S)lp_CzsWeZ*#)jLe@*bXCJ4xj2D(mbSW2IxTg9&0pG~rp$~6|OoK$AH@MBM%h-kJs*x3zbz0yex&kIOe zparq4LirKu(;Il$Tn3L^sIoKph#UbI9dyGFJXwmnPGaF&&1=w+RYbH5_>;monUNCM zV7=!EqR4YzUz=>61iF}cin}c>*L#bzY7io@yq%S^@E4FOS7!xW4A2$rrr#x5^O+Wa zxXzDH;vYa-)jdy&`L5EVjL6OHl~JG{mgGMq)xy5F?ST-V%lzz)d>m;dbH%AO>4M`f z`WhS$y#n2EW(pgGhMynGHA4e7NvO+O^b9WO*F+q4-;l;e-L~IetR9)6adV+}r}4DX z*Aez8kP^rI`D#XvKm4el65Buq}VP&lW3h&DDtkugbZm^Zn#D2rI2O7g zA5v-nQNqEF?hmlGeL4Ek@?mosrB6T#ohS@$>IL37PIjUp-8%&JOSBZk@V>wWy1cS8 z&d;{*Lxn4$s^qFXeDRQaHdL^yFyndP4aXc8Xsz#ynpdf?Ou{O7vT$^ z#VW7(0!;5*2$@?O{96Eb2mHbwUklC zMfoW6cUThfPhK>VSEIZ}56!o)vz`&VI9IG5MITyuc!nuLmb_h%LN}4F?||bD_zVgX zpr@yxynsD_`xpAN5Xt8erJuW(DazN*lz%V;Kw>pGK2gyN{6-TyFOg&}>X&tiQWT8OjWi{RiX47>qC)aWWG~n-c5CL6bXH4zLv47tVp!~_PqGr^C`ZrnUjUeGIf6g*=-_y8^ioP-$Zh;`LxB^#z>cJlvAaYA`%TY zTI{6?dXMl_9*r}t{yz)SA4q_1Ga*u`S#lbQ_g#MFwDQL+w~$|kIj&s@+EW>cxvNf4 zL{eM=k%2mR=9eDq+%ET9HaXnSgfX!ot}8zw8Q}s?fD0bmAOR{YecWw2EHX!LI<*n! za{YkRFUN~9xVz*^@Kf%5XMdg=qtoIZqvyr!WlUrQ^dO(Xf)YV>2&J z$$;)5nF7kpT?^X3pRb9@XAD@8*P+EC3Z^m~mZ{g2tTa4--|=BWn^g-19RnjMx#a1U zk5Q3fzDYheYoe5&6cY%zo+k&ojYqH!vSq509$W5Ji^C-P(_aj2r2Ym6D1^|=)zqtx zWcO;o5BD=>zfXuYHdoCU@g%XwWp1OA&5)`m`I(U?2*{TL=;q1`X(4L+g$EJ1=myhg zKk!rCncp?ZXLK>4sy&s8$hbK{Y1v+%-;~X?_9#WK$wqPHWk!dJ1sEnC8>-1ut^iz0 zp!+6yJwj+vJ~p-v&K0Gsit&6XRN+1m%A_#x?rtkrAP-Atwv)6pWP2$eop2uEub*30 zH`>-~IFmAgxkl_6u3>-+UeiJXq)VYcQ|%-zOz-NcX75OT=UVT5D;O(6n1cywVgE~w z@_<&*P&Kc&gy_U2tcg5oCHE0Z2%WO0%|Ohnmy1QQ5#Uk--GFV%y;puX7KxS5Tibf9 zk1bZCZ?vN4;JN)3V*>ByZ^U2(RA4KlbxcG%3O=SE$o21X-(3(J5pgjEbru-<0-tjP zUqeWM?um?JYIBTw=b}P5RivdjY=(^zzc&wmLz6$K&5swuh|(e7bVvO%`;bu~oKrlc z;)`TQJL6>kR9RAThua!A2gsKe=vLr|etXV#&3IJt9ACOBbH>nm`Rp(sd`Vn>YV$fo zBxam8s0jzoXE*3hR9pQMR#aEnrY=Id@*3;98$s51>80QrK?%pd`}h9?y&IDgO> zy)b-0VRJASdL4w;v-0)J+jCRQ`oh+E59;$0PEnWBJ|}bPXAxdtXh`GWT%AOZ3%*xZ6Sq%%UP@oSG#8BZlS zr`M_>(oOvf&B_r1<2CHl3Oj^+G_C69o(@{RJ@hjk!X*8DP}`#_Zf%T}pj>^wnKO{KsL8)2*9RfAi@A@_s2N+;a1?(UI4j z5|Vs7@f2(AKFNy!mmTQJs5cQ}#^GHcS68Ydi=>$;Hl%;+MW-?_(Pzzh8j=ZN57QrP zh$?K(nJ#GAj+|g2uhAHi?koyj@Y)Tx56-RxxEw&Y_9wTh=0#mA5d|L)ha$h9o6F|G?5Lfe=T{?8ib zoc%r5<{-eu;O*^iU>(H+be+_oq7ue%kWtuK8`R(gQO?powZ^hYsitG}$ypR0v9!Jw z%}5h0zt%}hOy-3WnGI@Q^BwkgH%cZn%+NJq>H_4;3v|We?Ku0zPB$@Me)oK9$4^7O zcBM(h`)+`?MQw^14x>U*<@UR;&3mnca`zY7kwA_E%I5OWW@$-8W}`HQPf!a(15QnC^e+^DZBYzz zSa8Cwh24MoOS1PWCMA0HYdW{;>Tt<(al=5$AaMUz0O(2#$(5?ao9%BJ4>-er*Zw#<>ZipaC~i-f69o6#@Cclbu%HI7mfNgf+>hRiNKd)|R|x1X%rM}4EzZEy%}KpN zMId3Wp6t;7F7%Mp+uTp*V5`poi`)FMgQ-GG;4`V)Nv2^Hb+x-$07{T;hF!1So0x9k z{sVZfg9J#<^pG@~b?ORFDh0hj7_*esJAyf)Jx;@^_2Y}A#vT1G{hP)=i3NJClV8%b zH8$tqKebkVsm@Z-Xf2DM$c_h|ABzCpsX8Vd0rRF;4mgLC!VubJNZ`O7#!gOiZo$3gZ8``g-&*t5?9uhurS^0pN-O-EBk9#I3UJJ8Tec@A}gjt*FZ2 z_?Yx!E3t8@%{J%2`PXFin{>xV! z=n~gURaGTL1pdxK9lJgW6aGDqJkMcYpc+6U2E`xOPMFY}g`UNu`C*f+Yn(ri@{uPq zGr~@>vWY@EyZeoO?tk?!6e9R}E(xHkgAKoi6N*)YXv6xZku3_Zwz2lBFyC~;^`6mH z*1Pj-u_-S0FS`*C2O6-!Bf-n-*6~T zX*QHCn=|^a{slpSubULmRnO?giqDL3P?hQ%YwzB-1moZYxz_uwndclByb= z^yBGXCjiT~Vdj|yA9{RdJIk-MW~h~@vG7rR^?&*P=YpS=f&}QBZ`J%|<8eAR#uQg4 z?5^=}o!I`LzE={Cq=s~T3)1HK^fi`;5mm#Ra_3CHK?=n;(yKXrpXyfa-YCYuNVER8 z-UR)x9X@ zk8f#J`3^th}B#^}`ZWExDR;)%iq$?@{ukF9l7%x#g z;@FDgC@AYCd9#D>1;{ul2Xw3J>Y|*=l1YSZ$Kklf|NYpt6waTug~k?}pQT~;2H(Hx zAs6V5&fq4xMQA|{t+5PlGBOh?r2M>ySM3}lLcksexbi^v?5onsDBM0uCeP^XjZsE9 z+H2JP{SavScWAbhK3`*d@ljY7meI2O{}i95W^1Z0d^b>&RzPpC%OsdP{mS(=8Q>}a zT^+v1E|^fUY}bCUITtzIBYiU8(ym*}h}mQ;YGLhz8b^Nu#)P!*XeI?b6KrFXILj3Pp08i#_^OMh3eB{$E&o@UIaTA7(ijX?0)6>{B_ zf$n_mt4oqZ=;u)RpaB^5iJ1Z%-$8m~tlw13fl|eitbc7CW>JHw%#UDfPReR{Yz@1m zFW}yW8An+g#;JFjzZ?Tx6`-3vA|;s*W9J(BT_GijC*PRv{}f9}3$AKFFlldEt9l+0#W((Zik9g;cIGyFQ{fgk045wcG<- zaLoz{5aHRTo91~>i7_UN-$=oh=|+B=#^n1O_9i>)cx!!eg^i}N)X}dQA9(Z&2w*|R z&bD#NsTfnL*>N+PuK0*{>i|~`=-TkC8cCV!8FcC#CW;$OtdgEq?ZVcLh+c=$n2KXt z#&9P=>*b0?6m`_;w5cs{DvZ7TV~OfAIPxP)HW7T6BzKo_)<70SnEznp<6RQL4r z7?1C({Y1aSa&so}2F#Xr^iUxK+6YhH4zg>EX{`?bhEHfks~j83&F3$?Ed2T}g}{Af z4WR1^_p6KW`&03RT1m5Yx9lAf|_&wZeFSRAcm7T{_D-8b)T^^}!MYmo5^PHJ|u zCpkR(v2tDtI1hDp5bZtAwk^t+tvT{#kGbsz1JnBcS|OW<-EFe{2vVELy{Ez60GnQYB?$V_e+#dLh$Ayv*K!x z9WuW_^(K=%ubk*B13EN$->ZRZUWf~>-5~+`ZtFqdT(V#E4hF^ouZ-e7*R%OR-%*LR zAf^3~<#XV+ZS13Z^i2WWQ-+TfJq^CD=vPjSoF09Oa-MurnT%dp#6 znEoN*t@p%L8^YUtU4`A*`uIe+x9^xwCs9-5=%&L--vD*}2aUT|Z@Q z57C(S<$|Q%>cs&IQb@B(Q zF*u_2cdups^H<{*7+2wv*IH=byXF}C!{C$1Y!lWGf-dC9#a0u~ZOI5C# zpk*zrTafV#0$gLDyP9FtkjW)SsjWx!XKM4Yzj)LQ#Q5V^XCIka+=s3PtS76QOCjZL z-ZnW$co3Qx6e(R4vHB^uf8*6A7MplGxJHNMYXWp%=1=a`uMCD>bCO+gy3kjW@SP?O z_erP-p=2$;#HAeUem)|kN$}%9{B@$K=Yg5KUU60h><4CxEJ=BvcYxwh4ld-WoD%f}yeNB1;TdrCTyLrlaMjWp2NmG|oLWCi=lf$g{QH22DS^(Y5 z-{;-XYMLan{ei`I^7svR5j8Z@)M=A;zP@qSKfhi*>}2oRw`Tjk;gC#8WH4lwYjG+& zvSt3bi`z3Wd+2)wa4mr@&B*59AamwIS4@z#`+z;hqx#DOduh8#0!~UID#JQPT8KbS z)Z5axi=0e~{OwwyNN(j3-=3*aq#t>C*7t6~wKSw1z|ZnP0yHmyZWA2-Ox009%iEq= z>!izs?0G|e`dBX&&cc~Qz^_WHXz?B!jybB5>C-)kchHw~mD~0;%_9>6qjzK`GCaVw z2D&BQsuc*k7DOL$9Gi#I|8_>DojL!wm9uZc5S538GiptgCt|Xe&5tK?=PEM%wadV0 zQX#Y|h6ht(t0?VcR{^XaY=ACWCzGA0ON#iBN$1W__C6tm8yF_&xX}kcegS9t{23#b zK#n{~XQD)MLygu0{|8+257EM6c}zjvqDK?%Qga}?F~3x3RqFyHSfthnAbhY{wr$dUr9iMP_$&vcz{81Eg32*Y)T*|2(Ho2?IzS&^0cBu#JDg6;Tl5CEXDJ1w zS#j@0C%9Y~4|c5wYnpjc$i#7dPTqD2SbkXZ@u=<#1h~#Xmo3?0!QrOsnE3<=dc*ER zzQkkFv2ubIEB}1$8DdK8MZD8VrZ%R7;(RdQO-}l)H3_=(bB>Xh`ywl8&4vO=&mxD4+Z^x+2md~x5rm$g`WkVup#8wTX-3UsqBnZ4Q6JG}z!WwL^t_ZmsJImfk5LU&>r+svU~hZ}Bk z_Rok`*689i>Zr7Rr-3@pm8O1&$U32n(rR-lTwMTg-GFZWn0<=pqV}1zUI_nm9SlOl zv>Q)wEaBEpy;OhD+m<%u7>`a?8m}tBe=o$LpS<}&VrZ;G-$tsQ)b1ZZjA!-(;JO3d z-@{&0*oqpQ9Dea$Rhg!5|4%ychGnjj`w>Xd<&1%1>jOUM>}`K}@qZ zjIv(EFTLq^MT0OhU4`Q|?*@pj?9E~fZJg5#o&(;Tx|ym}l}nt+f5sxZ<$VCxPLT1} z3+NIh&t}3SC?Nm!#J=^x({fZovp-fe#CJ)YP4ih9)T4-&{#I)EBww4kfq$>{kSocH z#9+D9W8gSDsV)xX)eGK3g}7gV?({no1mZL)i`0!JPjg;jREHl=$2oyLO0v3wNHtPF z-Y?p2aHeKa5i>a9w+Y~3Kkp^=RaP&bAJRBL8JuUU;R0N6%?b$+F;Y3~c~+c8C;QJp zE2ESwe6rm!lE?kMW#WD^mwTcRB)((7`diW_m6z?Y`!#1zHd>o%^`J{W^7XR*{@%cN!pbi= zGIQj#=N#o9Z#&+HO1{1{?`J!2_-`Nazx}9hK$k6(Tr}5?a7`hy*fbj6e>zXZHVcNAK~*7W6VG zW#CfB%%a{`93tvK*%)1p)!A2`cy$!oPt!#oPIiYwNv`8aNuhE1jFd6351xAt$Ui#Q%~N^>r<_HQ-i^{we;^AX8>1YT^kb~=Em@}2zx!f+@W(-Z}2NHIoG(9cEl^_jTij*l8G-vZoFpzB(x#ifMrO0aKx#${grB`LR5 zEweFd%hdF9MSK}&b%0mX;#-M!w&IBCvNyWZTL)u{N8NN>`dt7QT)RU8 zw6jB29s8&fquklTn1lvB;-DVD`3yB+QvRd5eAh2#*6|4V~43 zb1N8;Ync>T-$thoEhy^4kRE3dH%Mxo?k`@zMcqB+#A0 z_yMP=|LNYTbcxr)!^`s&4PA_ZK^l&QPbp$)-7cG3oiFqc2D&c$iQq(jgt&mBG)VLF z%lR#`$8p>RixhZ|8q&|AfG)1n1Sd5j655fS_mSx)SGgvgxc~aaayk=L3tSV!k5>GE z4d@+4UzOx1e9o}t-&m-56zi_S`NP_VYJ>WiVEYOX{sb$R1DVHuC${=nrB2dMi6B=$sy80{c?d?koi{t+| z7k8wS-+x+ux`&F(xCi=P|EjI+2<_*;FYKb?BwT~Xa!C8e0o`&e778A7*ui_Otx%IN z!CO1r((c1Jv>~Yr^6x#rg3M{F&}Q!@lT{KJ??CrAZ23b&S!fQgxQ%mNbtA3XCxQ1{ zJkag_O94L>#NF8{&2C=yA~XMmfnnEY5ZqynrmABf!JC?Eq;kThS6#?| z8Pi@Q$Bi6<^gf6LE6Tps)96fnpIg!MyXoC|S{flm z4;meIM_AhKqTs5;t9Jg?uLgycF=y*)#v!F2N?z(~&NoIRuebCaX!k?x2upcA+csmEoR$b1o#?V?wXgAshBq8}8~!svZjLs8@5$_Y)!RZ+*)F5L z?_f6o+*F_&|Cxh~aPVE!e4;gRD0(^j+TX6{3)32!84X zIXja-nX=}{kSGPX4#pDGIolXj0Nga7>&t~t>tK>8h_6MMx9@lHMe~brIg?7w)b{UZ zPd<6Pq1FAq6WJve&m_s$w{MHRiFd1MrUZoOUSLe!aVtO;dH@$Zwm||kL?TkTiJ!(_ zc&Xk%l`-|s+l@b`T$B&VBdVrt`443#3`{R7LUC-%f{R?#1J7AxON3QnH`#FB9-sCF zqNErv!2J$%>lwP~$1JZk;KpQ}%n_rnR-+1Z*uyPeICq;>KZ;tHR;?y{(i>X*iSSD* zNn+xox7bSKq%o4Ig^yKCKn~G#4#3R-x{pVq+<6r+a?5IM3M9Ez2Yp@Mh_Byp; z)-p`hO+c1{?GDYZQ~S(%^?{OLFYEj8tQzrH!PpFuBR_?*5?zkjOIg50~>w_?yW z!47bn z!1^~A=qfq|FIMdp`NMft*E+iN~*hc%T8=As^^+t%0OO6W%pTYVZDG zV7<4AKUtY!S|!-zoRSn>*O8Z!we@e)AihG%J`dW|Yi3F&SkH^6VCCaO-A-j9H(h50 zxZpK7BtS*&CoG8~gcJ>MNgi=+tU|I|DC~S3CAoFIoiDFp_OEC&`m|bXh(DCPUVGOY z2`#s5zPY4Td^X7uvz7OGeA5`<76RQk#S_FO1GcPJNjnVD!_)eC1@^s7Q%2z!{J<9P4MJ0>`-^tm)0$qJvnm$h6;9YiSaA z@VXV?76aY5t1rELY$op=6~FSCI9#}L)XU0GQmaf6y1dt`eLOyX$Ps#f#l6K`{O(Tu zSIz+IpshCj4QAMBKKb+Y1;?Z+z%2o~9fGmd3^*W~zt``G2_?2Z4)MRb^|M_Y(vebl zQ3-nG7?I#AuOzPa1~tVcRcX zRj4RtO*|EpNp`w=nHv6 z+mRr-?Nj-FS3WHfJ4PPk%q4oM9qL~y4PT&d7b=kDCT@_j(=Ya2)`y0U-ghW$aLHqPzWUm(DmK5Td$3Y`i?MpJK_DTz_3R)U*`B)@DPx4DW$- z)6>wSF!;GVHBG_lwALmPD$!=rFnb9OkZ%>x-6^G*enU>X$%shtNln2oli9M8$ zCS}P8D*Dg__uHXe;89oxwqB?1`_Ng`88U=K?r_LWuwqz*5|7pKpfJ8IA6X!}%^j_L~wy3N+g zvjya*0nayUfbMtHoX*6)fFG{S+C8XeA#tu{!6a`LN{$*f13q5LlGDu+v_7>SkZJ3* zcH%Y3T=fdb6{J^a#KYb=PIe=#90Kc|TA;gCir8wXS45M4nlhU+Zkti`bMKvAm1kSa z#t%kusi=C+E8Zb=`!}y~VlVnG&q#y(lWcqMzDloi;{KAy_HqW-43Pc+UfV+g1m%uT z-HQF$rn)Rw>5{4c`{-{<-6#8({6+a(bRH$Mw2kl5JP)noVY5-6p!A7wefy!XxD}`k zL+nN|r3Fn$9sn+QPZ1KJpM47+HD{AF8b5Ch=<55`tLM(pF4SssB4JBxhu86;v&dE# zge$RlAK#69jcysjS%B@<6M6YAL@uTIg;&5>7vO@=4j}>JFh68~yOg%%DiI?OzCbaJ z6E2>bu+&XWdCp4ArQ0is!&C=d7n!g^;Ar{`Wr*BkI%($T} z#JzUc#3N3Z5l0X^%m&x~koIi^y47luTWx+JQ-31gdfFMzSfm82_arkg_;LCysb>uP z@XiaXw&6xUIs|tocR=xImj1Od;xc2FiRgdP;`&A|&;@XtfbO@CxbbQl2(PQ-H}xF% ztv`MZfzQY~Wi^@DO>G-qHd}z4;{37ar*rm z6}&eKX$SD%fCOmy12acgBM<0L%x6ZNDuzcwDD9e4#Gqs^{Mmn~g^~2dEXqBqWR~ryM(p z+}@sCS7kf^w-e}2s9PT$X2X7W4T&33S65|t)(P1BQrOHvMs=W~@xr0m)4I#-*ysC7 z^S7v=a0X^8V?8&uIl&i3%@Uu^R2L=%fD7)+kN{Z?$Yei}&|hIGdz&GB+jEd*jnr4o|Yrk5k(E z;sbu=?OjD&n4z3#+~6+kia${qBd0)kV(aTT27l>(;SX&Is`0Nq(&* zxEsd$Egn2Ei3U@w?CZrP0jNn7x+Aav_cze3aULKz48IB+C{d5EFXhr4$rzN`ZCyk& zd-@W7JAh{`v#-U-H@ID37vqrR9mRk#GxZCKSt{=wZAf*^7bp7-zy;UBkN^=_7$7k! zoCHSwfsTVElkmD=?B5Xo60Uuquk~F)F!s$>h}2~ApAQ#&1@lbT*JQ%q-w6;}5Nqh+ zbsUbwCKG-GxP3sE!QG!QU!X?aD^H=_5s&p(UZIZfs|0?L8IyO!O$R*sgz#Jpr)6Ic z-(8QW-#H7XE;&^%M!uaXMp)`woh4T-0Jz{Y5=el??_W~<{<n$>$$H5oD2OeC*T;a}u>Pa9#E3TaH0cq_jfz+^D!`d=n3_pA7)rCO^^N zrHV!-9&%Xummwd$3yMjIGCZ!tIuhpX*-olPY{^X*eu+Wf&0kr~+ zNGa2l)FG~nGOp2Htvn2L7i7`X#-!dwNA%kh;0^)Z(QVe}i<7}(49`C#W}m;EWU#8f zkWhcwvE^J}by9ke##uy}Dy38lMQiu1k7G`O-hD1tKDdWhc|F!8$y8(^3vj`EbdUfw zHT;Mk`I<7Yw$N`U94z;U#K3bGeCHi5s}U*7B2sc>gJr;?vLzWyFU4FG4P8S+oB3eY z@88`ntC;CIYyB2{CJ(vaMu6^iN6KZo{I4WWQ3knNZ1#a)jZ+Rrtu{*^LyfH97Pv|L zoPQbIHY?&7s|~MvSk{Vkr8)E@zqj4NR0)kCuQmtI!4P*8=xRIm{$!%x=c;iyZ`(Zu z{riGB@{x0{(@K3uKeqQ4l|c@z4JL5D~b z+hb2nhD&(m{j3qG7c3M}gyq90-l1+pE=By zyS!)=rN0~dI1sH(4REJ`F2&;?SQKQRaSQywp>^X}D0+gMt;iN}W!Dv0bsbNvaI@Sk zo5boGdr6Ov1t1F=N*8*4C^gCnh{U8w(jDvV3xNvKG#$(J4vs8sf$&oy*Nj(L)#)0&+ z8KB#3cWoqJa7WSoe1JLecLi(W?}H4p*+5w0;}g^`+SP8Wz8`)XWZFbTij~X_Ov#)J z7l$+OH&HqpKN0o1V+im7?kv!aZPAn>3zan$GK`DS5W~Q9Ivz^JJ*^c<_NtS*)mhO3TyD&u>;LZVE-olaiG?4Hb-nsEi|GdqW zgW>3OqLT=Vg&~Z+du53@g`Cu%=Yev~TZNTdR$3LsDG$T8F=*(yM)f{rFEJ;V8J{af@60gIMB`BeYhrB>aPG7#X?<)IzqCYnEP2G7u2(Hcgw2Ga zd&=376Si?6==!n_>}Lx=7sK@(>6yYBc2Lso&)E_ldMKpD>X2%e4|6dlNZ2}g(eJK* zaI+P#YkVD0RnT0Q8|wecMKoWc7t2=yLBjE|PIsbl*9PT%RB+AKvUPU|I^a!J?&CR>pYK^_mNC#&BEJ%L< z*Hn-IL6vG6DDGaYV1BL(Mqx?c-3ar)a_eY?y|_NDXo{gu=kv;*jN^f=V$KVfo}y;` z5zjU3c5ya}-xf}9wyBw^4se%&uA`sgSE)|tMjX?6!D)*huu!$wosF5x=~$>dKOdDw z*JcVV$s3U3{6cHzr--!3{b#G(FzOE8jm`~!jLds?3>fNo6=&xvQrZ@H=^7w+A? zO9XiQiQ2e9vGKEn8ly*2=8lUx5$KWERUxQ8vcjRvMv0}PbhcwOZNABvo59R!bMkhs6|apHz19O)64x}&QuS)M*_KS>p(Xhy9=wFo(hVfC;`gz zrTD&ngj8_2XIakJbFGkdVWxuwx}|~Z`0s`vo>bG`$A<4sj7KM8Fw6ZPJA`8L5LWR4 z?gr3>Grp2C)?<8}>(Zr?XL~ojM-j-3xwZ~P^ni8|)vUg4Rp}Iqm!GRx*zPGwim&lX zZp=94;G+(0=HEAjpi^G(UK}LfO`z*qE|)K~TFc~btRXMTmf1@3mK|pDnt&1JceI|2 zrqEzYtqj2fk^ND|!_0Jn)mv5KmUlN3MJmLl7hI!20z|OVj8j-py;LSx z48q;?{2t-#d6|eYl^r6&-pAY+Sn#Ul(zGiCF=CKs0Z$pR*a+UM71l78OKt9NdPkIg zK6uQ9m^10V$qe|6ppg%V}vS&}KHAslPtMoru z$?>DHkJ3Jj9Z4lTm8R@nWfsxTo1;Yktt!2)Ee$s|JZCvM1U|EX8FK%pN&~_F+{Y|df%5pf|9tXL8!MUs+CPLVxI3%T_8MoB6!IC zapP*N2%nN5u+Vu*Q}LmpczV(*bum&2;O+xmIKHW>f6pEqZEjP$`g}o5bH2{OaA3zT zSduJM&3jjKpoKC{%qCjGg5al!ouJPd zd8Lm>Tano1R3GV~FH%ATNQPw+75*A?j1>z>On;>y)b`;BXio8*`9|{b#j+*f9cL|h z=T)plEqHE+{`Z!e@4pTP9^)YaI)?4LxBRJ%Q1o!;a_Q}kN@X_-vc}Xx;JTK^52!A+E?hY zkgSphYhwR=7{^W`vUI31V|pT0KsHm+CA|rtFr8C3A?I5#MBg^t^kaJ~tTBx+*+B3% zjphGb@OyQ~K-a=<_s_)bVXC+dt4rF=o852XL^ioenpdQJ(`vOQv4wMr8Y|{+720{P z>T6C{asOoU4$PudtE>;Gi7W|ysmS=B3-iDC7Egd~$%aYW&$0;Sn#T1X5}|KO%Wabg zrT(-kkGuutn4wU+p5mnh?vsD1*}dhV;3MAB(P669$j8*ZLRAMuF1gd3vP!~ zpj(?QK%LV|`PvP7(xyAgQM~jAA=CD%N_4fYV*yT62I24R89z`K2T9|`-nByWvZdFg z#T_cYKNo{bn;r3>ZS?=#|K8sO&mE8ey*`6RVa7?S9NDH-t+l?!f!dPh&m8zLAsRuW z5I$2Vw(fWJH)MKiur^j%@mP1OFhk=*{H3XRy+(d0m44H)(f?d1L~y?6K$mdOURNBI zh>Z#)x&1<)mXp2|lw6&WaFLLF7E$g9sm>|# zk8??OCxO0MXWUu4{W@C*r?dG3`rdXm>AqZKpFRePln!(UrWFxn~XPEjP)HfJJto$=-TT_Pf)Auu{qC z{bM+j)C`kBeDffC53sKO3v?011{{>Wq|5GTN8?Y$e-(Ee(qmUPOA2&O8XmESgO{&x ze01Mg*X@w?*8i-1^s}Jewt}nfQuMTteo~lR@{IR?`TqAD9(XSp5+J#7CL!EveN0wK zIq!S6Li54K_uR-Z$m!$J``^RJzAztY;X3=$VHVEpyj5*lzRnE9*tc_ipt)li>vuta zTucPGH$b;xunmVilvy@<1Y`T}-$gvJ_&6~&0|I5(twIb9Wbf5>_*W>u&SDGXJ!&i; zNJ-m97=<~P`xW1qg%T|*x}gK>om-%b^~(@D;DbCRY0=jFSLT9CdY@kw=918tq2syY zEt%`JP1-N!vV>tc(4qOq6Wndfy1py9Mu$Jkh!H(lykoV&XKs*j{SN4McYpP}s+)ay zZ_+J0so{|8#oUW(ou-pKODdXiFXOLWVuvkeoXT8h6X0}JP{J%ubxq`~s<~+4sxosk zn%WH9|GfvgU#w_2#zk7TVkWE)mzYto?8$lXtcg}-CetkTlnXxZ6&DhYTMh7xQ(sQ+ z8J|_m-}4LH-(_dGW*MqGp8GU(0rCa+Wk`UY=$;Ivk&{1_iX5)t$X|+pJS|c6R!ftg z`6onEmAaLG;M1ZHn7?;3B5|AQne^gxx-9ki@aD9-cGK<8ZmA}4e+N7kLjnY^O+ec5 z@*zs~OfhMpV-Wvv?{!wIfF(`H;Mhi{)gnf1&!UMLkGXfxS7KIX`x@`Y`w|r|JS7HF zuZkuasy1L<{RDK0f}do?eqV~OXzhu^EKhzMWmPU!$O$jIrf?|WkV}uu$gK`aY5wKu zniMUt##x9kNC86B+VCzT zN2cYCK@-7hi{;!u876v@lWnc2St5Uni$vUJCL|@Pn`|A(COx-^JrDwPUw|%SQsk1? zYwIiI@vru8Xn%;#6c+EXi@5h>!Z6*XT7j5;rg!dQ)&7V_Av5wyt2}w?3smg9sZWKX zFl9(3C>{Z>TcBVd*+M~q8f6Wn98b8{>4!Ur;l5(-gr`dvEHXT*St{$y{@gr&F_&I) z{9zZcfUuZD@8g{CNxJBSIYD~CZuV7G(sg>V9iSbcfo>J1`+H?q3B<8pZnzI7?sw?= zdBGu0QgM!E*5hZD=QQmZ^_!-hSF2jdIpRo{wZVwHpFOCUf70!JYBJG-P9y}lFhF-0 z6|tmI?M(HnC8~4VONNQaw^){Z-|#Vh_X%jP(d)RAySFDx0<*6-7DEU3v=insaSQ}4 z@sx3ihP_Z3u;r})E-cV}5gGhVI65)AA(5gjymQ<gyFqh6TBgK|r^m3?l>^R(L*IUDiHM$YP^e zNh<*_zb=6$K`Pkx$$L+*Y|&JSAT>v6>tvYGUIba@sJEW@`jvtjMPROR4_zm~g#)@X zHm_mZK0~EV;J3`;52GvxoDG~=&9k6ezg}R9p?r(hFEN1l7M^Kf$QUj~oviZw6Kx7* zp=*f6VSJ`GF6st&j)3F~4|HDz+|4*&InfLxEhvUMdp~h%lx@+^&B1L}zQ3)UY;e~+ zWn(WH&5!t=i?HHHxRfA6=n&1JZ5*cJoYWzNoC~fYAua;YWgnR%6S6YR`??s|d~$Xs ze;w7@XLp=Jgur+o#>2?W6HF=c6PhkXmPeKdmjdfRx#oizm3U0lo*sq=a1lZGyZ7Z@qEhU& ziI;iu{r*>}xj%wuIWGBsiOdDu*U7eiAdtERuUm8ZaO}OBl&572Yv2}mlg=ag&X$M= zd%igY_nSzd`;}hHi%QRP7wz_`Z(69dN7Ol}uC%8pwZpr9i8SY9xA&ExN_74@<15rJ z$zMBzvOP$G1n zl@D8SDoNZfb14|+OkB?Ri6QDvq{&D&$i?Kq#%6HApNGZ6{|(@xfG&1eR?=iEliekmh7v?i&6e z2reF(Lj=dydDEf&w3MzfnVSzBjt0jW8t7u(S~$wXF;6^R!gBZ+?y%G1%GRvDd6Htf z6i@i)!?*>XVj1LA+RBVM9}nM+qNx1jGZxlGq(G~-HD3&FcOf}52OBrQqLoU^CKy(jFkBq3s~v!RG9&xx_(O{$i+IvgI?VUJ%7R>tg2 z*wYb%0T%;wNjd!`P_qo>rP$$#Yi+b5Kj+O%gkh*FQ@p*xb$F4P&-63%*kxH3-%yil zN0ykz?JvodQB7M$V1DF5`G40H1Xr(J45C#rO<6IWWy|JJ|%bFn}-Q~5-N zmu6mKM4NhDJf3(qr?VN(B`8M%MPOwKeXxsZ&k$}DbDPLsZn~KR=3b9DKmTuWGwIMM zf5;z%uCKTMu5tbw57?kviZh5w`VQV?;4R%v3Z&xlOR`!jB|PT}CftD(vewHjMcXG^ zc_{%Fryl5pBJN)tT9NMAVoj(S0&z3cE&q>4*3*(-LdN5Zr05Sk=ZK_4Y#AuFBp0g>Nzb2D3%b9LnYbE-vVL zp6DqmDaaam3{^2n`lfv;LXBm3R-XNeOwc)4%eo0Q90z4o<>@3REP?jv5ihgATxOkvz$Sq{?&@{%`_Yfvp1|yhWj_u=FvBKnVz{LmMsvF)WomKs>r|Ri8Js3TcPdR}q z`dGD>Z)*9ZEX3f+jFrO2{hHAQV9`akqG>xrEEMW6xQzJy>J*s@Rb24f0ha)D4d3Y= zz^1enSL%Lv|9f?CX!Va21*O;#i63|T7*W*P_-Pic_`A^qYt!0MI(I4sDos!K;d9(T zaohInDy3qJkAO=Ey87x@r+1fv%_DhD8)YLJCks}}FxKH^us4{V-Fsxu)gFSS5fVtq;JF?V=-R*KJ9-;I4DX7tvP~7#Xci(hv|Xpy ziWF|AwH{9+E?=C}3=`p-IwpITXBzwdV1pD*h53x9uh~XN-f8uUjSh&H7apu6zw|-Pl9?i2yliQls3i@Jx(EkFeMO&gXP@gyel&1)T2aq2v|Cop5#V~S zOw2EUuz~@&B%r&L5k{RbU5qxkzPYfi_fB`OKH2#hv*nphzidQbu<4Z*sx^>8e9H5d zq=t-tr0l-cUG4I0<1v1>a^gN`gY6gKl7epWrliiyJsUm6!Ss=Uc9K^XhK9KxJyYz@ zzj{=^XlhCAWS3r0vp>fqhMh3d?9Q$x4 ziEx~FeK#e$BO)30A51WRWS>VZLIcLFM?B2+407$)~{b zjKPqhm#I#cs1SIdWYO(>`%<^MIo5%8A^h(2D3P-~L$97Io{KZN8iDWu+BEmY!Q;16GX_lQ-^ushAGPIjq@V0u$-_gXUd=`F;R z3H9fZ+DyQu1YNF67Zp}f+c)8;s`O{J7i7oQYqF`+7?VXh9|UsTYo~RDlTGI}6eIRP-r-9c|gH z%Rs~dy6dY3mF{8RuN$^K>K2H&3%90j{h=J6U3R27v!)~u1KxjY-~WvVYS0ZQ>+5~E zX60QQ%-s4*4~PHN8^bGnaQ;G4QbEw(|9wXooVY^#c!J*Lb;5w%eO6(|{$6Xur3`G? z4rNvG=Xvm4ng(=*ji-4#iC+f8C$g^mxQy`QU+xKqG|yC#^;;&Ha=JE}L@-HlUI?^_ z`XeN7n?e{245%RBEu{2%G?gqdn+d=?(1NZ}TwDq(H1ikpL8-Mnr{lWd|D~>RF?-RfN9dPME*KNXu!*z!I30jB&50=jd;nHC)*A$dy4 z`43i>*8!Iiboq;|CdxJmyorZ!<3*KZh0!=IDb$E8ylp-|8{VtF{gp-fsZDyA3Z62? zFKx}`uC#i{8v5>FI3)?!RXi|K*nnbmx_a;S88pv!mzGZe1vUO^dKrdS8lkwk|_%eRxjCy7|6~oEmVMK^F(gg$?hF zdUO4>^DA_>xDI9Twh z|825ef_4I27SJ`J@;_O4nak;#B9__6E~T^ilKhLLMzJ$RLM!`om5yD{>D$e`MW#kS zZc~J}rxlYjkp{ijsSC|6YEy-*t~_jj%L=-D2W`AwOrJ>bi{<+Jah`5wgwtSj+v=sh zQ)+%vNUJ8GoMP7UaDJ;-%;185Oa@!7Rd9752Jh&1QC3v2I5o0&CfZv!mJ${(&i~GoSwLkt#fo`^;h|p zA)^cxz-0$rFa8RopIT^D)n7|Xx$J7OiGIc=(}n1@&Oo0D9W3mx62m2&CVAFk8NJzL znSX<07U;ZgtR2n`-R=vg@HV6XTt9Gt?$$iaFzph~#SgoXC@Xdyzfi+2YTiDmPnPP~ zA@evYxRc8y`O00^1|e#`TKyrx&FVGLrL?$OsGP~$^EE_zV7#25%WYICmFX7g+mH(J=KrDn>I-Aahu`a1J3f^exg|j%x8*=#* zO&||kpgS`}Ojx|=eM=J+pyy3oaZhmp%f&=oH=^zRN9ox!S$}cVa%JACF0gKqyfS;#=aldc<`HRc0czYe~6n1!Z9Ke7Hp)uMwB3d zczHoLIBb6w#GTph)maF!pJ|b@b9h2qvKD_Qa9wcgT3y|s~8^M;YX9>i9hKzw?X#?T7e47q;2jV-k9Gfu*#`XdTBYjdwUQfv+~w0z(wB z(vdE13{P2yPkOa4u~e;i|D~XbHxm6S&??Cot-(scd89-p0*IF%bY-G(#}Zrqv~F^S z?VlmbCj>-77PT3&oQY^mIW~ll;_AVpCX}S2D)inERatv3qHRb&`{*z#)yGXUPqqek zga2;=pqs;&$s?Wd#6(%c#*`iPzEW(hG}(q#3O<3d;t=)Qw#K)(QM|@d^$L7C`MCYT zV7N3Z?4UBQUH*c_(CN;`k6_*CJ?MUK`CGKlEcn2qgtd;wm#U&X{Nv<(tZ;3*?;rZ= zEZkNKuTXENz;p*xf|9qA*Q4L`v!Qz!Bm`-Q z;_It%Mc!KyJ|H{YJu|n~vdyr`c(wSn-;99L)>y5Okk-i&v5AZk}&UQ}@2} zo8&A-rSLWD`+14CuLp2H zfbQc7SC}1~>NVZ>ufb!)$a<;HYcS>Q(W_lHZuwLadeJct6+|BnGEAY zP&|~q>vAi@$Hk44j;ME9@T-A(qI;^qsg2u&8erGdv(3e@GW9Ky=Ilb`9NYry${#`Z zqlYZ>PowngeiDL>n>TtNDT#F9a0)wNP* zl*UF*Pfqu4t5i$z@T}O{0wgKm2dnq;77j3n4a9S`ygggUm#VE+6MgRn5Vd)IF(u1OS3OMNl@Xl+IqGzY`F;^NiS^y zR~mGCCd~Y62CpDU+PrElIwu}}nWDw~39>e2#tSTrZ!|ZAnd{Ba4P0P99}n`N&*Bmv2ivGMoZ`+A^Ut9LbDh!Yzr6|n zJvTYfO+O0WU(i9URQ~8{TdK%<6=%{A!B2lVTx_HtUjlKHO088R$*-BUpeRDwe}M(do~9ldQYzgQ2_ zJ@Cpc&r)j!X68^V zgTYm7MaL}z+bF#r!g*9D=I`FUlnY;2R?0l;mQS@s4zopA)<^y`jg|wEZ8HA8fU5$! zl@%rkDdv`r%ZGF05OmqPh!Q=9{Q26*tJ-KXcAu~`RlXbJLkDf=%ULB zFWxBs$YCcDDz~aZ0bEtkpAtNkmTKhB?u!5ryC?Qfe3$%(*QcA;^D##d=|mMIy@ zjYh!FNT7vr4xYz;0bK$tTr@&?xU7wMJwD~=1{V?Q+U@)>1DgC_`t)0U8OVz$rKgOa zc^H1snnxP=tj{~*S`xLCH>oDdw!>M*_JhASbo(dU>E z9M?kEXzPmDF-SKD5h5ozoWz@%hF4+VY(=7nicg0=6JPE5i1%eRfbpOOx;FUV%g<=c zcR3X_k#}!4PTtqiqFzlPJteL8XVIHKqEFHU(Y{j|VF?y(BZpx(WG>rbk#5C0rTB}C zpa&i84*rg{LHFWv_gb45{YS2J_Nyp6)`v^+bHZ`80)}~>s?X4|5aOAF&nnYH%-bm0 zWrqBd=pC}t{bFXiy}wl~4QW^}taX5RbwD@$eU&_h;XLyjkqV~HYkpZ&42Aw4gSBe6 zjYJszJC}0|L~=wF>{3qSJ_;Cwyk;-$EsW!|=kkjA#`r)*B12Zd{RX-VZy!JD56;px)OBc`^K|M@3Po#h~Qn!l>*XuP-Ijvy?dkymP32SR(MF4VhEenJZx3OZgLS5nq7 zmgX`EaCJfV1gd3w6gNFYt_bNz15>KHD>?~wq{oe9)g@V{SdxIHPihHHxp8H}KC(pW zm28cAd&c88%i34tAD@QT?3J2#09Oxm2Tq-Ot`DAk1HB;ipr!Rux(~)MKe@pQVKV=n zkWpq9qv*9)y2-uCF}cVTw{Q5MI4#eoj@F^~M2VCy1-Sa4`}gnr6ty^7GU{H& za|ehwvT?T@)V>SWndDKU$Zc^&O+K+(3AbfRZRT-9yn8EZGM?Vw3}dUDA^YbZ<%$whKp9nwGQYFXdAxR76L zjgxy%Ll#8ikxsYSmj7gx@jC+X8iMW#+xs7}?JqYr53`4nttJCeGp0j59$Q?|aHqE@ zYC}zyhO|~g*l1KwD^Kr-4d$ZB@D(&hFLCz>52BHKLK49I8i8)D{8e4V0&#G4+xXZc zwsQ`1A9=%H&X76bMPta-OE!;VG5OnnojX?PlyQ1g_CP)SZdY)g zGzML#W`81QBK!BY=n1BL&Ztof-)DdB4rds1d$O7HP1Q^kG~(-i7~Z!UHXTTO@HpWl zwWqZ_ziPKd#$578kEOc;@?ZkGmr0PK6ffEfZ>Pkj(VV>|bE*0Hz37bi(4X-g7dgbL zI^_p>y>_7@kt}qZlA>I>vzx|9VVqm#Qnq+9oW!Y z-l1&BHp8Bvp?!Zx8H@R9tAgtNa>c05SubS=13`EFH+6V~u^?zP!BbC5sw`Lp9B1D_ zS9|m&S@vmUCFZt4%$&g3G>VzZ`LDvDV8A8^^$2vaXIuo`J*_1(Lr1=o$N*cj6mrF5 zr_Kd>2%G)Wbke~2zrD}@t^3SC_bUnFKt^`2eD}hjA*6 znSC*G#0B>a42wkWBX{ZG%&Z#5%22XB(hNRJM@k)8MZh%&-86na$4m82gxl-899r2w zUHqKeywAk!29rb2vO*`BQAZ1A=8jEERXGwtQuX%A8x;gn(+fXbE8ibWvxR3EgXcpQ zpxaisgj@QaEfu4j`l(7y)hTkR@Gdf>X?Y_kubTLeaAxw((oKlI4@KdZqZ#V7>=iCd zs>&=jfs{T>Kl|~7XRr=#3AzePt-skNZ~k=8v9jskEiaVGFIY0MDQT4H@_4ULY)3XC zFEs;onU=AfVg$8a!`tA@`|G)R|Sb?tJjXjly!ccem?!4SK<&N;E z0Ls`C?99#3Xm7@L+SXCSR^o5F$5U~>q%VE#$|mhvjMBc1qmRy&@#G2|G^_vKVfgR4 zS%a?L>MRDcu{u?W#8ITe>h!8KzOuBB$!{6|{uckGtsi{_y85lQss~WfCwLC#)p&Ma z+#&G$=9JB3bx(vGn&n#n*9LS~odn%A6(*@aD$*M45d0)hSAya69~xRN!9*q47yJ-z ztm^sGqS@doD^OEI*bG8ni}b;I@fTjdvP9^e0m$Q z!LHA2@GRyZ9(TrLq@+@dBhFX@ouh$=17|+H@XVLZ9d6 z$mB@gMJNgSgrm=WJ_>MjG~&_{XqW9ik!eCJPKH}Ma$lrSpoz~kF=JK(-NF5v3+SHp z|E2z${J6#Jv0;+p;DDX@xdnr9Nz*nWb%b**6Fw&T(&oBjyL?Y|{Hr0+vz|%t{zz-u z$2bDI9w7p;%-4VK#QryaT|u{d6ua7}Xf8MGveq5hFGqt>5T$zFz0C9c$Nm)@mY3>W zTmB|QzwbVq&o?Gmy*KEEi&67b!5UgV;s|vMTuj4&>jt_qhJBpz-$;xkIOWqhd6z$b zc4L3Tb<)koR`YgQ;I7-dL7U=JPWMgPyjq8CGQ!{6VZ$=910~8hj;wAKqJkpuxw(Tb zJ3(?nVlS1VxN1ocBPoHy`wJUl#kJ~7L`k{guMP0rED~$IPs7)9k_?nPgLl(w4+S)@ z@BU6ddK@8zHjekf1Mzx*?!sKI)Nm|RH@vF}HLgj^t_q$c(bnc!NM;>MQ=UuB4;4JK z$iS`)1X+?k@lUm^M@Vvv$W>8yE)$|Yvt+(=setPVx|hM3yDrSfJJLQ0JFQ~W%Mcrq z*FIu1Z~oe;N2qy5DOcM1&T7ZB+afw-^3wE8?dW}fuBjX>3Q|w|gp0`0F%7t0pi9<@ zZA9>_nQ(N=Pwb4%Z9nQ%RU&AlQR9ihwPG4c?RS`O-&tPzAfsqe= zGYDBky$FK@DFjcK{HhR|_C1YzyofI=R}VU$@>?>@m)uUzunOHYR_MQk4q{?J9(+NU z-y$V<3YrsZ!rK=kkn|wB)Td5_T-PirJ)k{8{=1y}Djjy)?K_TAB>{>Tf)AN$>p4dQ znyE~Cc~iJ`M*=#s;KT5sX0#qB!la>A6+ZOlG(5l zl`!UENwsZ0f&J@&pzH4it&#Cr9Y(h@sJQmK8uT}sAniF#f!9kyh@YJ0EuG}cMiQ_i zL8CA3uI;~2RPB2vT!{i(+MnH~mBgDnZax9=27#`=sRZ&F@>tdg+_vDb^&T>+{j^i^ zrO-5m>a+LgE2X&Qc<)y?*^kXr)2U};f=ne?z2yi2D9XVMc zMiN^V{?NOq<4usiKYXLWSPb{B+5!)iqN>b_VSClOld?l6IoGULE?HV1dY}XK>Rv&R zhMZ+#mSYH9|Av6>j{etCah`Ac&MUOvgz(s9PM$dgu*xv_+VbUR|*C^^Y11_y$R(I>(qE8jKVG!I`_ zeAT6|AA@yYo>dnw`boJcVf8!gz8GHZcs=OYJ!l681NDijRu+mYB@%GMKo{*zE|<0G z53hjE*X!@@v?rzwQU1GEII!$?gss$hw6Y^n5QDHcCyl zOG^r~kP`*C;h>vrAQvsac2hW!iB8@QV-7ETFrrJbKs!=!#Dkd6lPL+^`pBC!TN=L6eFF_{*e9}_A0x3M$LP3iAxgu@&&9DM1rn7hk})g3mgP4 zo8$YMN$3ebV=;oB*%_JB8hL|rM3whHQpcXI)qJERwVunrvwS~L>qt(G3umb$j%Ggz z*+2$=7g3;l-9(`PKO0;!v!5wet6(nY?Mp`-?N!5pj%1P`qm6}l$1SnmO_yDKnx+o1 zaleBRwXU0-1L>seZK&9dkE9INf1^QHLiSz7Xy`Uhj<_XXY~H$2D#qv7djC&9*YCea z$e%75U1PKrZi}HahhlZ-P;FFQ75sFZOdgSracCtDxwiXN3JLC4HEotzC7ykU=Q)rk|e=9Ns zD>LB6f-d8{q7Gp~dp=gqlE#d5xKz>45vO}q#fPi@*vcM6JXA6a@8dju;RWG}OU z^In5gNEBxxTOz-rHpWqj+j_u_16``;;&`Gr3o?QtyH)08=feB}vjfiUB?|WYgyG>3 zt|NZGh<$1iyz@r0g;az(X?u8|VFoe}>54#t4~7qEV!FF*m_NN{Vb-+MD)96(#4q^U_Fv zCKYY+Q^(I64qNgS*#t6fz)b{Q6pWg`)sd?StS#2~>ODVl_`A<|C*p7Xi?RxwhHDYszrT;u?6HNFVrhKoCQ*gi%A)M6_@qhZnK}ISp4sR5x`9b zU2O=(m1x{qI?^fH?585iXt@z9LvhU`#&O8D9G~JYKZYPe)GO(4rNP*-@?vpP=N|ig zbvrhRnQnsqK?dZXod7olbZcs)QBv5}z0wPhpj>4>{7#>_6Sl} z=CvD}<}#vOOTdauH4Di5q{p#0v46;p5P6{w(9$~dHPz>#oP!^G%Y~h-zz4+p19W{i zhN6BDoUc-8oalFpKjY09%J*%$O;4!Ri;Hcke6@TLnW<_ed7H@)J7>c0ErKlX^*2SS zTIXUW^s&3}BKQJu(?Az*$$iMD@UR>ATFP;p368S#D1VCucKFVbAyy#&tRU&8<;OxE z5 z@tR7+*X51hb_J>&Ua+T_g=VKUNMw=96L5D86d1Z<*1b#RR2C>ZivIq4=k34!MF!~h zSC*_&$qHcPv^IX=$|pgpAV=Y3bz}GX=e{*3$rtw7IV>oZ@(b}b2)1zQTG&4q>L0Qr zm9vz3$Pw$Na^h`8)m#b(p@upvwf$Fuy|=`b?_S zF-OI-C+rFxA^%U^P;_m^ao>)=47v~O`Q{TMOhCLpL6^Htkt%5ZrEpQ#VzK>~`(%qI zX*EXO8Wtx!^|wyz#Ahj{Og>433KzeWSnS`_nJQ-$Kh_k-MqJdW^7u&Yp&r#=vjlQ)9{gv>HsTF zEU2xu6>*y1Z$%n#vq2Z)6C2s;HonUKOL>keGVWEKm0~EytePqv=@SnW%$bb}s>pG< z@Ib-(U>SwO2ba&wjWf_ZWV=ZMJ$d@Y9IU?qHwSdZVBaSBIs8)j;6mhEQ=vuiaoL;8 zTdY9tJ%#7BC?vLol&+OSx<3Bv9$w+j@~>$nm+6UVFKJ`;rq%fY)n}6Jy?^haC&^D+H%@C;%epfd^>^hfo`C zEj-=4y9ZYBn@Ik7s^w;L^ux6`Lsy#(I8Ww-t~@G7ORu43x(^Duq>m0vLL4@F6iz%I z3wjHUMd~eoC{e3tT!!=!y#*&UUQfmH#5BI~z$jy8t+a5=+-tz4ED&!2=#nMr!D}~F zkZa#=xGKKGp^vIdbLi+xaQg6_vDo%7?bh7}=+m4*~bhci2^GcRviUJkdFX7lqTv+VW`J?Gs%u3otx zSiAM^`qSl^_G+Edt#jiS4Rp{>^G(o~JgphvT|2>a^+ZZYUe&PN4>yd;K~ z+vyckLrQt3q=qrOxP`>QX&_%X8e2rL2f@bw^QDLL5DEUb%cHu^9~_x1j17=ea}Ju% z=*7Ij{d@`N*4Jr-M8&cmqHed>FdF+(3UKgEDWtzmCcbEk^JH&g`ls7g`wP~((WG;m zWY%rE0yc*r4Eo!NTWoSwuGgm=@P1Y)=ysYt{7{i|#Inc4R@Z?&P?8JpbqvXQZ($Qx zP-{7L@hVJDT{0AcC;RJUW@pX0<tx%AjPw_Y4k@nVVy3rfb9c>@bl+y~rc*MAaA_RzI#mw4l9TlhlV;yF@GiX5 zqoM=yTMoLa+izt@Dc|J7?vG*Wc#eGU(~UYhwiwDhO_I|!jQi45P!|>R0p9@=<*+lD zwhr|PS$cT34W<9nT0IZlH!d5n9#sLlul4eCWCv_Lgj*Kt6#30>Zi^q-vQ%B(T+)1- zfZt@Ay%i#^kQ0+y$x->eMKCp3{tL=_xx`k29nGo;t_ex?4G?c7=(;)ii}_;@z9b!{ z#~;Wbk7p?unP|oCcs(QjW&%tbzWT=~yFN}`cTuamFR^P~ zobtkqVv|g5{lz~hD~Uwsyn+Dt7wD!{M@61(n-K0b&le_rtaB{7ab&JJz-LV6NKWky z$O{$i9h;-_+9gUravc&r!iPD~AujuJJtw1>vW(yj7Y_xv)u78^V+>1-AfARf;7x5p z_i^8*?4RSCAIpY%uQ~EN zMA=XLyiP#WJ%nM)-9ZDabJc<_VWMHm1Ph+|q_X5K^Q|$OmsH=DJR>8*O&?V=a^8}A zw$;mPO4=b)5Yv-F!av`beGGYZXW6Ba+B89Z7`Tc6`w!Gf zgYLxIM?^iI@TISsfs^LbFh-{F=kA-RuCk4WJw0&6~#!{fIGWsj*~jd;E}iJpUIR0&jD`TRP6e?48+d zvNSZs%38iQ_NUw408-u~4PlvA&t*@NL~(d%b3Cw4&5ZK|&rz>zy`XGDLoEnFUCJx?}AS$gIsXVssrRR@_pM!A8{mAPf#Wux0Y=V!3brUP_iW^z%p z$j{Opv<)Pm0*J;#VqYD0h+!g|Rx8@=%o+u~2a;MaU}dQVA?*3XrVt*_f`sKbxtQt@ z&A7i8+6mSHdFTY)I-fc*b=@JNU_VWqm%x){6xU|^x!~cSEsuV3_bPhDKYAK2gAT*Y zErRlAi>_K0*Ubj))L%DmQa(5$*G$2+18x`SV&>l$LQGVwjy7&UC}Lqx@$toyE!t4> zdCc^VLqsjJyOP{ow>1V|I}Q11T)HBm+~w3{6gIQz-k&9X*e#u@0NifSbvk49XwBVz zn_8-7Rp6*>Y-sU54W)$;O5}?uw%w9GIT1GclZYJQeH7Fg)~|An%|E@+FCoR)@GptB zTROow4}jYPx?i_K?M;l|HYpS+{w4EkOP*eVuptwgd4!4PZBkwk%Vx0`ma#**GqAWJ z|GcYErfrakrX47O`L|Z{M=M2CO$^}ng03?Xov3O{@S?11ApM+m`?9^54d&cNNffso z7RooV$m@nu)huKqbC~5nvUPNI<_eNROTTpI?#>H-#b2H~KTQH|ALzbm$bwPkttJgf zKGo$x>e=-pj&GWV@~UzXx@e8~wDsgDbwS*L+MwJJ!I1FeC~0LcfTr= z=WnzDw;y!#W1#PqWpXL7h8N5j#QADAB?~wls9wfL)jL{xZSTchU#vsr^pc52#mA0& zPvE;e_=7wCvak%tRE0=n<{6d&?f~e9NoU09LJa*~c!k>3GGF&WE=Nfdv+78TnM0Ud z*W2k9b~4dL9NRr2ge&i3+5U?0?t~{If}t=h2E`@pZjK2&-y8&8^--GZMkVFwB&9sL z$7?GL{-CSrx5g=IlD|oC;nI$JJFxsqk^S8pq9Na$V3IiVBMs?z2qV6Gd}xcRv#O;A z>wQC@Yr))`)F5S=I$;6zIxEej|Csu#ZOu-{COqp~c$So$1WGQVo88kpf60Y$2NgQr zy=VDOr#BzeHqcaiwCK#?Sb;nYgRcA!x5?KK#h97KqmJF5#7;vTGzaV5h2!$l=aleI zK2$YJ+{zhkh3pE9X}u!{E!rDK($}B`lr!;ZZo%$Z5s!J=5_u%; zsHJ#@saLl@5FUzxMwDQ`+!*K%29Wgr(2cn*cz=%8Xrg?I>T+4V`IDKu9*tz{Ii82j zto87`q!CW%o-|NUP^IC#^1c2lv1q8v0hgEw=b_>`kl%68&DOAwL+Ry&7mc@A?WjiR zTAx%D;`mLh)SXI95dE%-S_>gat~3HaL(PZLUdXD&iiRgzlLqGbopB@oGa{*19NtX${4iTaU*!@8K^Y;Ty7@ zg2{`6ZR{-EngRcBX z>B?nn1q`_Jfp3je(WmM)w2V`ngWHQ48M*rAD`f@y>j-L7RMjUFBJXywZyMuS6d&IT zrB;3*wB*-@u)74@8PIjAEOAp6H2ZL9bLj0WuB3n?$uEMi0PQS-w7f}#6UjpN+1CKs zaOJqehB`Fihtw=y>^W;qmUVplKX2mmG%gkd+*#1oGLJ=GTu`PvQEX#LE}lkfU{xZj z!Gx!_*b8im7xZ^!MX^s(tc=%}3`#N8I;{w@2#A?5eq8^OZ2~ys46N`H5I5DATDn;+R&)F! zIFBW~kPFsRe}k^6-vb`$o;i%>x*TD$t_iw41@|LY(Z>tsn!(pdK9<%;zo>O26sd!c zG!_*wDH%R8O>b4d4Pzu$c;Kxfst^kS<6#MOxv47hGf~|(t12t0@q??=9vI2v5whoC z`QD~Js}?HYF}QvDQ_@JHLLkLEtRI<^`k57>+^oOmHFTsWqJ{1S{J&TRUD?YorQK#Y z`RZx9NhweJ!ussFLCPE*lka*98oPV=8V<>lw@z_jQ`e7Wd0s1yy?+(?hrS_I$w>TUXm z3)pnh?_bc|&g+xyiX(k~t*jJ(fF}gs-?s|7h>V#67%I<6c08%I6Eo}IP%+^#-DK!E zX8Da~5Ob5zd+~J@X1|{(DIrZ~HU#@{op?cTwb zWB*B%3hX~y2i+u9M%LN{6tS7@kkxX9@%85XOxmqlj#m@Jz0_nn$+B?zCyoB}#A(kC z3*oV?Ns%`{H>e~uRH`G&OAr@!7s0-u4bYv;5k8i`$iAY!>*vm7?^X~aZkmwK$6S$=(HogYrVH0$%c0Nr#eyGEk zmZkKOI?G10@~D+b!wrzJ4w8e)wPjNp>oG;Oe{*n${KHCXbaaDnVnyV-O`4len0qZk zVLk;MXIr4V!)DkVmf!I;MWoE`GBgloOX0(SDVF?jhdG&BRd*R;T@F^leXoBF#GsXj zvn~|>bPj4pP}4eup0*{l#V~C-5brkVh7O64Y@2agwT^x@F_CDWZL3xcwjNy~Y|Q6X zN9Xx`@wfFt-$m!hlfXtPQ3x4L;ihJRoW-G8%T(DXc-b9i8E|(%*M_dy-}`r^dWk4= zwNwi!huWW)^+tOrLYA-&tFA*d)RtI)3ban?Qm;GdVe4fngmEqXy8k|buW6p zF97Z?=7FSLjx*N!QLBYwp%w&wmn zxldJ25^Y7oW_@zdAI{@>$54tLCT0`6g%_O29Cx7M{ z^VdhVCKHWyUNjP({KZh;@U}A^e_=`BcQl)Qab?y<<-jN1e@9YRSd(+^Z6iHV%Hj;< z;Q(|qc#k|g#WCrn9c?N%eJ0gu_iXB=)5eS(wBJF7sdUiy5qw^e$o;DdL9$~t_9UZH z*-IZP$AnWTcA(tIJ#E7axQC#NdzUJ^9MmIE+^R1rWzKbk3$r5Qii&kxM$N`kJVOh<5cq8%{ZcaB!y{J{xF0^jJhYg)&|g8OWXIA5yW+&qACK zao=})#kM7EmE6m=jgATl`?P194y()&g#PS=vHed{s&o`+ zmZOkW+EupZPGCR5CFuG_Ohkx|5FfP(a=5JZ~RZK;g%6zmAP5!%qVfA6@ zRF;l3vrjR6X39)oC{!E*!j~AGxF@N-y%XHGT!C(}bqiAxxK-R|B5uZa^&4i5CZJBwxUAx=u-q|pn#H#^#qoE|%mgcmk9agX48h^|3*!5!6O z@1jfS+=%QxU5SFMod|Z_%-*v-O7u-TENr{AB);b~lEZICBc{Xbr4!v6- zxYW_v>;Q4rg4cHJoK)>hSpjI$Z zn?)@15WU!={_;niuJW_XqfbKnuCyit(G52qip?~3S872=R4tEE%|I>S-huAr&3OAJ z*Kt)j`PleixK?hBw^M>8Og(DV6CRS#!t)hvg6U!;d4*vL@?6wj>WKh!;R|f($TxEn zKCL=v9L7Gty$4;5Y$k{!B`6j2sUz~@ltX-B4u?q8_Mz4vdU~cD9!}@KC+M-+`k^vj z)sGljNVqP%yTxQIk2ER>A2I#VD5JrC#0Ss~$)-aIicMWL?wxQjHwf@FHK^t|)P0J1 zRKc%~_^@Er-Y{_fhbllInl^=(4}NF6mz{tAmYdH^2i=v&aKCjNi1!h6qmT%>mTMlJ zt%=Aj*LEs2OE0$+3*V*`wJ$M?tVtQ#haoV-LpfJH{nWO{EiqUJF`N+%lM5`dJa||qVC1&I&S_R>_1oh!( zqb(=rug24qkBQPc)R_`1{O&7=U>*D!bg?|XpK}z)=%@toPbDD4We*)=gkuRMI~$|o zI$-YAd`gdn&Js=MpBNX?9iS6D`b`|?%_yCb>yx#asbOyOx(dYm0=jiy;dIXGA_98r z@Vicyv&52dP}b1V_|`52x4ew)+-tX}cgfUyL!CePD`fQ#b_oEq_6G1X<^MZELd_3AKUEfLs5wh>5SQ?q7ckAp$!n z+%BbV0W#Jv=!uAKDXCtv&kX;^-dVs`akPv3gcf%Q?yd<$2<}dCcQ{E-NFc^Z0trrW zinkPZE#Bf%oZ?P#D3n6+Vr_B$&$~PO50`V6dz-KKyWe;3$&ZKKop)#Eop;`uotc%h zxZ=S2-$aF-INo~j!137%`UOpVPhZO??|uJwU$NOoOMFx6{`ak`Unto1cCze2GjlB+ zbhLNRAEu`6KC02PjWJtCOiK1}r&r5q^V)ApH)Gx>Ns>O>+#8) zPuF|fkEih`>%#+>8WvD>QegH`@b63*?E$lJtWL-4YF7~ zOZkU{|C^4(-nYxY;&|7Y?f=!oq@R=D{*vuq{ge6#3Z*mU&o#RLtJeGHoG*10Y}50i z<(D${|2et4a&cMUzh(jHf7~I-f9-VFSsz$HyT*q`YN683?P~vn(_Dvt!2;TNBiO2q zmj0c`O@E=tu2WqWa9QC0patH)epF!1KIOmZ`oaIfs&f_DWdWB3To!Oyz-0lK1zZ+z zS-@ohmjzrF_}eY;{v7fD>Kdciz_>rXZSFsQZ}xAmq`x^qS(ncau66mp*|4tU{-rG- z?R@k~y?uYhmV4xb{-qUmDd)1l|F8w5&0L+Tx0z8J_2+1{>t(mlkf6BkQ8x+WnYuy$ z!)pF**-P0LY_V7}Q>M*q3;!=F+uvrSf0KlyE+ckpW1T^x*t*_r`8TP!e?v9J*Ipgc z@3GxG?7G)xRH4`sY< z)#AS#;jiiAI@@IdmjzrFa9O}*0ha|_7I0a>WdWB3To!Oyz-0lK1zZ+zS-@ohmjzrF z_;1!ZxX}Z&a8RCRT;5Q0b*4Y!1lZN)?uh{kamr-zpWB zn*DiNh{dv+F#cK6zycNatvW9)$BR_hcj~-!94}U3>r_~Jj+dyg4JvL1j+d&ijVdf7 z$KR;1O)AWt<7FyrvkJ?^@d_2TMTKSN_&XK0RfT2YcrAztw-LraOIFwn^0!@`Cv~w! z3$a*ssPnRm93<{8bzTnk_k#TGCQNLc6AnrMe@6%tljnlN62RYa6*o8ga<0_<2^E%y z{Z|se-$@mgm;F*I?34=2M_6eUc3OqyCoGQ&JEOu15SE%S@tYqBcX z5c_FV*m)IJn6S3Q75}3Vb=*0n-vFt6?Rj_ zEkT$~h5f3+N)pzPF!A9#D$IlZd&+n35hiWV6Yi_9`-Dj{rQkOe_Lwlqw=_IbVZW=m zUW6S}VSlJFZ^D|gFKyyawj%a{O6<$uOLd+v`?*xuD-~9Tu%A?i@LGlW5q3?5y-{Ih z3A?Vs-m0*2gxyeK?^IZM!eT)DRTL3%1?UYD=BC0bvcFr!O{Bsq5w=H#eWJoD6V{zD z@oVV}$;MIz-huda5_Mix_H%Ha_;pfsUN!a$tFYwiyy}EK1o7V#Dy#4+U!f&BrJ^ztHXXD;))-pRbh46|AjE|!*nXF9{bazqWMd& z!s@fXg7d@=GpMiz?0-v`{AE;OpRxbF3Uen+)NcsWR9I$pUL(S$6DB^KMTIqHzXxIB z!&wQFC`~}hCO(`?o!69oDVv1lR$8OTxOT zu>2~l6=8Jy?Ytisw7){CTUeuI#^1 zVLmF%N?067JMmRv{_NY-d1X{s0AbY#6TkLTVS((w1oLjG zC;nPhg@v(yh%oWjYAP(8eQ6)!ht*Y>ltI!HKdhm`BH8ar#fX2^RAD{Y4oc|@mNLA8Kxm@Q>%+e2XoIGNiR<)*I@mz|nyd5rv0p=lwNPRG3F}V6Qtp;2 zYykU`kEGd3g$-oCBj-sOTdS}^?B@`r_-muW2DASTBz{{J_Bs1v2hp>g3LC<{lv%>s ztFWQ$_aHsdse=j|#=fK_X>?R!!`TnxJUPFU3X4@E*+5`}9F#<-xX!rugz*rau<6#0!gh}uvd6%V7nqgjKK_*1)&$9jt@( zun{)FX4nE-VH$OpL~H#|$sm<^u83wQ}Kj(!bq;4QoZ3%=wAgRxOfvL%rVv8N)t+ zhwvLbfmz_Bq?3FaQR^AdtD8%;jY6wgzOr zCiAl!oWG21ezpamBm2#uIkW&7`}#szCWoN3^LCB1#ZGE$O!Im1x~{mI13j*t{;cl9)Y89435JII0>iVAnXDe1Iw5<5Uk)2 zZqOFmK^w>nxgb9jfI?6dl0kAv0VyFV+$Znf;1N8Ar*IcML9RLdpgZ({P>}0$AXvd0 ze83k9LwD@(kox`up2KU9adIO3=@a-A5w%2%BLmYy%k^Z-*VQ6L!NMm=Dun z7EFMNFbTeduV6BK4Pg)t5fB2w&=;NhL4W89R`7=auz`$sWqex?>O%u)2#r9-uFaqn zl!oW{_6v9kui*{60}C=YNCcliVn_lh;0f~I;W(TG8LP_J^hY=g#fUzQ?R4mfFLZ*5 z?8|)eDLez2M;0TjIFtZc!`KM2Mj`7Dvfi)_cET>$4SQi9`~U~wARL0jAnOE2;TXvJ zfUF0cgi|2%dzsJ6{QVrr{9MM(7vU0IhASZR@t@!tT!)|G2K+*KZi0-fqaYeShaoT& zhQV+c38UZ(7zg8F0@Njq@=y+B9DW;GLvv^fO~3|0P#j7?Nk|W=;5m7}gx{gR=mC)s z4*pOBYCBD8(0Pl3EK<5!FjjY#rOSWY^<*v5f3y81#H z@Po2Y0SZ7tCoUEvN}2kquyb ziS1h04hP^ket6CPpYRy&Lmc|Y!Vm241&Jf)CxU8F9X#Mq&XM_R zb@VafjAVZf93fBHUIdwco`$&~Vb02K#24H3B<^H%m3gL7PHo=EaSM?7VsntW-zB&V zSKumKfOAk0dZFVp=tG*_*w%no?AxI!RDfydUl*Nfie4Oxeu9)kjzypDiP7pg9>B&4zWZ`V{W-tn9QzX{wv;|ud`#*{`eW&vTR?MY1#O`XSfM?%Q^%dzc7hJj z5xPKE2!sHzf!H`0LO^UA4q+g+mFtW2VKSE!M~Gz`4Zjn17rGIAhpk+TuY-)AWqf>! zaIyVv_6I-qcF_r@H{__-0(06!=LzTgAj zk(L)*x#o)vRMw*@m(|1U`qsFbD?10O$|>pfB_Rquolq%3p87#6H7d1PljV^6uRi?2m(q zFaZ|8e3%APVG3k|ui-2B5+;NA^gNggGhsSNncw%pSsaVciF`IRfH@#>g~hN2mcuu& z6qdni5FcIzD`5plJ*>$J%k4!dWbKIo&SK})&6s~FX08eg4dA3 zjcYO6yliFP9a4gf;oRUIGU=#4fkbL6=Ou?^kQ5~EBy1C_Fk{~c&qH`_kU6T1Q)J8{ z`D6r1;~w$TvNdd&hW*qaV{FmGD5nue#@|xLbZjLL+0UT%^-rL4J_q0%|MavR@36 z66ZhjiPD@WzAC;|ihc1#Pqs475r33p!JA{rzdGA$Pz5SOC8!AHp&XQj3LtGrkaHwV z;#37AjuB?aKMeoy+=j&c3>rXvs0VeS4%CKPP!s+ueY5B#z9{{+Y^C37rjDiWHo|0I z&XH|PkU5CR#1F(4t=Ko>$=puPGtzFyzMS6%j5Or9El8Z!&=e$2M=;`bU|;I56G&O) z+%6z#NFGKU<9ta|&NK4p%D(9MzFtNg34ep$(k|WD4}<`SfDq^o!4L+a&<%P(5EwEE zGtQNLX~VJ=MMA1)ESL<#!O(XM`=Y}Lko-kA(OJs( zzD}ZxQ67=WdE;Rc80SlvQ64#0j*U1H{uPLgW`gAPHOzqNFb$+^Q$S>*k09sER^rIM zp|9vBc91lkmB)}fiz8v8v&5Husbi^IDT~yF*!2ByV_*D0&NJdmoyfkSr<7N8U#7w( zUCCz!7NIIzN2-5BEUMf1QZ-1|b~F{ACfy{G~U@9Hu8oneHIJ z4c8%(uuw=2e{g&ZvU1J*g89>&% zh179Dw)tTh=jLN8>t=buSVNOAkx5*^*f-YNim32nY$Ys|b4#)<4N?ZtQSJlPg|bi% zYCu(}0+pc>Q~<*#WevF^RDjTi?0>^n=4S2KZx7N&ISGBpuN$KSXdmfo(Y3Fp&9R6k9vIZ@*p~i|@yA4IZ0 zh^>qvhO!M}8x2F)?+a1v_hBn(OPZ37#Fz8l*Tcx)S-x_<An`sdr!#vS zb`kp;Wi{+-L3+bM`bzoxur7`K4Sggnv6q}Dbv>H6(l*35o`Lw?LP!GASBigp z!8wMn6z6yx$Kvyo*ot3Glw-CN*yd*|J|=x_8IbN2EPg$e z5I{q^t|?!qIujqD*?vCnZh0#c@ZY`4KySOv>r8EoME6>L|6q_qydg*C7m zjBBi1XTMX&)!0^lPqvo*&9DhJ!Um{Fy5*r9Nckn)*os{C<@_yR#4*B*b4B01um^U- zcGv|w;d|Ht5_T94f~*_uXZr&jfJ4xVe2%d_3Q}eXzYq67Y<353!>@1)jC3xse-SRg zO*jwBN&gqNH$c+70zbn~a23viT)%!~dj^d4t5fWsgcEQYvVf7kq#@@U`CficCV3nA zo|AJ(Tk@5BWL-?^?mGL|Lb?U3_D|0V2;t`bLdd;q_} z6ENDbv{9oCk0e~$vGfhnpGbczeS)-SY1h&pydvxwyo49<9R7qq;CDF4IdW`l-?9G| z-hhnNWMA5d5hnZM_eQ@Q$NnaDFQUf5Ptcq(OQjCpew|{<@!Esm|9^JO>p#BskdE_` z)5UsE=x8~gFYDoSZoZzSJ!1*Y2JT4qPqqhyUMVpnnOo=5o<3fl<+b|}5~uHobM@WI zjjWa|nFr_QCnVBti;fPl*)Ml4-Tb=}o5vEz+q0Z!IcyLSY7LB|zu8v$%j_-Q%}M4~ zntZ&x%WD$5-5NLK$-TwNN>=wumaHwQaSLTiFGW_!M6aPeRa_vb=DudXjWSir&Sx>iKN!CtF zjr15X1Y1LUklOJZgG)Ee-0?gTUr#Sl?hE3G-Oi>dAD$u8XZ4YIi4{s~vp7j@$H1wt zuUBv11qq5tNoC$Dar&&OKD2SAd95Ulr?*JDg+};`)(acvdH2fyU47Q2mh z-Ta4x=WUC-BPl~1%F#W_BhDHYY8iLoi?lBmtVo1JbR)H;1kvYy^v((XjJcILmKr+f>jNo>lPmxA0y~rE-;BhMe6U-z)jt%aEwdu(v^-fMY?3A^ClYBB5~tOL z>m@Se`K%8TDqFPv(BD4Q{S6y9sZ-I7)TFga4KCO)fmZB1nUS{F5mwD*i zN^Rc{Y~SiirJc2qD7(p1g5skqBD~gxJ`9+R#7D0M^L*sV8cD5jsonFl9oplr>85EN zibS-&;ax3dg|l_PM1s}CZsz&O^Gm6TYLZ*ZEt`CZ<9FP zBBG^XS;lni_2^929RWz_4MbE8cNeYK1m}FWt<9+mNK~D+Kq9t2Tdi8*ERo~CMWQrt z+7^5~%hGoTXxUhP+j)7&;#~J8Byy9cO=oF2Olnf64T7SwwC`YjNNS}$NsqQ29->7$ zIABub+GN*zX|;flaP>hHMp36-`D#P6;kQbQ)_N;BtF&&i@?`G^=dzU{j`#ufQ;bZc z)jw;Mr}fSq15yx2FQ_F3Nme9&?&o`#Z?+`2mYQaru}HWRHYknP$zL|__3f-lwAAJ! z5gYUzUS!&S%eC)S94{}+Z%CwNr7kccMXEoZL~B};le6-mwU2n!V3H!*pmGfkJ@lTD zJvI?nCZbT%hB#3HtLmqxiZgh|wJA@E zUwwr{^>2fbq$kd7_tf?@BZhAft)+V@XPJaVYCCn$aW%8w81o#7s?$X(PS*@03ay&d zXDAY}8$P-LiIlYH-0xMg zNq?YP{Usz~QR~_3r;_x$-Yj17tCINqdAH+gx1~wrCFZHUAQN0+P_rA&2G&Zx=_PT> zpf$QBqWMZb?%}Dteday4AyK~55kre^TVF3vU)6VEH!UB{4_+e4fn-S25vIO0`d#d7;E`^vvbA~!KLCb0CNs>Q2He=;_DVyJZrsi{_C zwRelO+M{fV(mwpL_3o=b#7nMF7)dShuao`4r>;tc1l#ECG>ErLgQGJoD!KdK&nM)n zDH8lTBs|z=4~dRSKmBf&tUsN>qL@tkyG?3RKY0@U+_~Aqhwoo8!UN>eXgRQ^# zN1PVNi@~5JH$!5n?LWf5{@gvq;sQvdqad~ANW^z`^el4e{=f!u4Q7BOgNm(4q@+=! z>b+gJs9--WHO)h6X4l8ex0?3(q*1GB(o+zJ3ted^BS=PX(z0yC5$oJuIy&vyvq{85 zly%JWaWX#e(Y3xvYSJ3V&HJv^oBqf3v1MrtYI%r6Jf!xXfPkY#p2}F6wkXyKwnljb zg<89Pc{zAX>b92-A&~}z#L38k$%056M-DP@plMr5PzBP0m*;Cc|K+fE1xZb{pK?gV ztL{JdztSaRGT-=;{(wYma4%KfY$-o4B>kw;z)4Bf=+;Sj%4!#MXXQ~AH6PW?WO9Om z1`VxxCP#x42kN4M8do_P@6hJOL(E4tJ@e^fz7$DE?W?=Ja}`pf4m^EJTSg+0Yj8l} zR);G`+QN!N_1BKfmwA~k@ue|*nqRMl zVI2>29o#U*T^YMDs6hiK-mB(60nAEdXt!_f_jyY^IbBiHni-{+B`_k|7Eb@)_uGz> z2KN0?#yehesr9kgqUkN8Xk8uh^%z#R!+j)vx(!mJfwZg%e=M52CD$jPBVo!WC=0U zYqDc@KH_*u_u^&Af(GKF_bSdQ;(hr3JtR`wWxOo~lw{B|zkZ49uYG`ohAl0t6cXt} zF67QS-MTWH%p@?hXb>Ic5zgS&GPJE({?RIBD#@Ju+<(IY>l=ITM+Tx)UWHN;QB+K zBi0#>ZW++6eCzNe1oRccntcbuY&1 zGjT3+meWWIBl+Q6oyjFS9AZu@Rujn!B>Wp>t)21l!Ht>6$jDBY`9B^8w9>glRS|7@0ntC0uG zBi){K$`-eRdTN3DXZD*lwHW=VQPMm}B+ii(vzw(^F=K&N3!1-GMixpqj>Now~Vc#j+Opn1H+8W`r$CnVCcb7719?Uq$8 zq2+_e`&mMWBcp)C=RR|bo?m7V64hJAs(dO0EsOfHNayZIeDyxwKO)v99-r&R^*bq! z*vF}SD5{gTt*%S~!4W+|0&&NkqdVoOT55}ykLGUyAs!*&K@q&Yn(}q``>WC*QN3lL z%|AxgsmBem_+HO`NXAvtQ{aiV@SZUtcAGuV%3fc0^?e<##nG-mL(y7#|LILnK52jK zYrI!$Sy*Q*l1xZSp4)lG(!-+<61kSpO6DVxtJ(U?pDf#2U~pq3GMg&L+DS-wphrxk zCC#mnG}+fTi_%il>L)1DBU)P4#l){_WLsbJk@Rm~(3t1Z}Q{ACQmca6N1R0oER@ zhxE=|b$|Oud&oy>j#@BVk@51{r}C-$`?X$qZne*?mDESNm#_%x4o#9TJ$idkr$^eg zUi`N-ePWn35{XaQqRWOR0^?$RI}RAMv5?-wYW=9)#@bvjo297N zqT@Mk$NZ^jjTM~sqkg(q5hH+XEDx6zzaEj(>nCYHWyPSDV`!ZLTYQ~vP<5Y9t7Iih zu7F-XmTO4l`ZMO6f<;&E$|j=#dMcR&Mn^^1qlxR~9X|6_NWqqRYs7UdG2wwB0U_KG zIucYhnRha|o|2ZhVoXd(ASYOIJZxD1M4{Y=k(5I>EZSSDn!lu<*6+V*TqTi|rMG0v z_hGN>?p9ns)uC68m*l0}ld)yC$|(~0C5;mwEv@(Qm64=FQv2u1`?k%zA+1DwlxtQa zB^fY&?U6ibvWr(KNhc*~+xO3#83(T1rX<)pOi7YfPW{v9g_TMx3FWbJsg)Ld;m`4b zTju^E{dGD03fP}Ga@EYY&HdLVx2n$7BwCxJ?P?`UwJ-mcDp2GSbIX9RJi{XE%! zF}YvcMy0fTG)Z7cP>@8r9oy^7*oLFBYjLz|$z+vJ$Y(t=m6|k4`WgkP_Id=3%B7Th|PE_Xa@DE%5XjE-A>#%ZhmOA}#v>{`EnV^;_y_VFZKlrLkma6`j zQ`e4{Y(pYf+KHvwk1f2ua`|+oHJ6UmyrmK>1*u#H?1SPSuRnjO>b3#mRX(hEvv!L_ z##LSG2c*nDs?|lMHSRkfiOhpvq__2W>w8pYuB?iQj}9-PW;s!--n~q_Jj7jZSrljj z60zusGVU$gU4E7niCloFxpXD<{(8%m?gMhK>p7X!RBw3!iIj9#hKj#;X*fxIR2mSe zg?Q*C9r|wl>{nScNpC5>L(N4ak=p*{{+8@J^S(K$#nIN0ihAlA%**vhgV{SjZ=l7| z7M~nfsa3b*tmnf#k`Xh#s9>v)E0{nfEmoqq!06<7HW`BI`YYp|C2e*=K8WaDgGv- z+e1jiZWjX5tQd04f1S4Wq}keWg-P>xYN2~nM7Vr4>a#sde=K*c*Hu!J^&K?m5o+x% z8Vo5K`{#o8{f#*jl9#1)4fY+ryM92IhCMY6v|6x-gxRe@++%v)C-nDmpULXJj0U;> zI9bD&c?sqDZ(muEN@XZyKI1npkCT-JY1=d)^Oc3N_^Ei}!Lj|)WJ&ZRt9ep$(zZXW z1=jGT-=Wc&Na&T1QAd*6kTtgB#mhI@tZa?MKQ7uPo%zxOW%f4Oaw|;lLpa^i5UWam z&}iEBvNuwUS*4E?sW?j;B${rkt858uSt+mR#&jF&#DqtNM6&WSuHC(9u|+)?5vzt} zxk?=I>ldl>ug_F%F5`n!DkRVrsa<7!$E~Tctz0N`bk%^Jt^DYfUqQ*V;L4aECZ}+%|{C$k(u~Lk53k*J-$aqooW>DLdDtmP2t;PPwqYzK{YG?W-Gv#Tc89Po5~e(&aa2HMKR`wlBb(I{g1t<{at=@qBRy0Vyu z=D0#>kTrLW4*3Tc!v;nV8xR^26GEJ%=K=HM8?;|u|)+~xr=Oj9lGaDqYkms zk1F$Iptq1&&gzimKOV`rJ+qdYwvv?(NqQu|TxqsHaa!-$Hi1R8JE?U=m z;`Zd`_UN6&5v`fMJKC+YW;pMUq-JvGj(j>+&@I~P^!Qx-}yT8ZKFqG z6(=IV8f`mQpir__=vJ8up1mrG{kazP0AkH)$3lk+mA) z6hI;^t5(`IOQOe~7>z`YDMF$=wC<|+(4bqMO=4(21EhZNQ7;vzUy@EUDvw#j$PNuO zKd{@Zfq^0R$ozSxWXqMm`4^f*8`%X#*?QT+qoX!W_&m$7ha<0kD*0%$oYkZzEx1+J z`|n;(u*wRcj6=vLw7TAhq?mR6;?Sfwd^CyHz5Ibh+E3t^4Xr~i&wi*$Gz}cJ*6N4U z_SDc*tNe85w};Y|k=j->k;4ar6)fOCW zpv@QX9jE2dMm1m7(rY1gOuavTxs;u8A|=(dPFGvkAnWb7o}Z16ku?V;$*m*>&W_$S zZ(+aQNaThi`IJN=z02VTiQ85$yu%NPk8wBl!+SYeYIO30Rcc#L-SS@=wQdA)WQ>G$ z#w*EupR+AL7zbwy=gZoQLU!|^0PS(=2I6kJSmA3db(0wQS z>C%BYqfS~i4K#~7Sz!{pQQI~iGKh>033&Q=$N=l7=?7~XXwSP;CpEb`zso!5=(yP8 z=VWZD-AuCBLnA2-Pa3xCd9L`)Wf_Sht&!B6lvMe_ucRiPxUS~HuSVJ1M(ATcjAQu& zNjfBbiv4!yM7~XUFXj}3TFm1($w#wJdHOfj(8B{Qw}XARR7gJSfU*I}aV-g!de}W9 zu=ktJfsCFEPdxIO-hwN13aK<|%#FTEg2y}F@zh!ggT5b$lM$_tPwP=Rc=SuXm1u3@ zHj->esudg@?pAkwhWOM>G{9~qsiC!bY9_jwr$%|sG}6b)pH>>XpvwNkGN)C3eI1F^ z!i&7aHvMdw&UE@N|N??(DbdZhdd=8 zWw$~|WTZNE$;!UXdu105#IYHRnY1~)Dj|KmQ;TZ0HnAxAWNV_AC(3f~Y{;W|$Ytl>-a~N!MC^yG>-YcOGvSL)Q=hk znAeZf)HDtJtx-0QSjMtBa$0BqW|RI+{EfElG>)dh>Sp>CaQu}`6)(IlCQnT$4>749 z>}IapW>QN-e~@WI_s1vNZqc5h)%`6Y)-kVbr{&ScZy&BJCvqz;2Iemzl3^|MYl+|P z9XT&0eaSr*46R+aCm~5kNgwZOyWehqtgWtS%e|KQNTg4UIn?oauBEZuUy#8QU7}@` zk_@J;YRZ|+Tv7Xf+YGEiYrQROEx)6dwddC2s{LR$r>iTPBbd*sYmu5L5@wHEj@m;fE10$b+2v#(0ybpDH;V)h-9wf#( zvPg`N-X~6aQd=0>PIbXYB<3YG*TCGOKeg8_n(W%; zZ&rrJ){VE0c|PVAO^62O`Ix6>9_R1X?Vn|x=N+^!WDV-o;Ypt{9zi=l)n=5^#~10S zeIIL(CCj<9hXxjW6)$OzgvLMU@R-yYhjrX^FJ3Z6#rfsd@3#w;E73DvvO~qGGo|2+ zZPsC3;w6ufc#zt%rdh^S$S@~myd-xg)~t|39O_y-b<35%#7mkWp_?02d;7k{cX#wS z6E7L4;>-anbk^0bMQw@B3cS>{@s&za1xW{zV^*7>xNP(o~N{*;@!-4fzea*sbSD%9fE zC-bzzm4@WTZZdvjW@K)+51*NHr?1kc3m@@ObFIzuslwfL87pUQ+b~JUf~4~7ieyAr zWNuOO=LQq6uo1fvJQ8j5@Kr)Qj<|l#foR2KDc!Gd#ya$XwY$d z&B#IXoi)Uf(O_+R%RGzQR%9k&%uCFBOLOZq<&8giaxrlDhWbl)hclCqi5`{xk(x92 z#DrKhA$BwO5OW(Oqz^fYbuwa|=~?=mDOMmwCF)0>spk@F-cy*{+FXOb*P`aSnLi=v zbZuR`XXLoDt=&anxOy@~_r!yZljYxeC|y>pqh|aUk;v?Q$)RuSCf@sIx8~PgbbgkF z-Su91>+1@;Cx=e_7KwV+-TW!|EyQsrwL+Q05_kJ~N2d5V$B<-2GPC8pQwQhP=bpHc z+ASnfbHhWrXG~dredBn^3l%4-ZKLAhg|+9>lm_X0=ueiqr8aT1@o@?xkyYwr z_d9+avm()>cu7?xa+TSav2v-;axAYAFG+~j<{Bi#I_9Z4xg#KV9_UBSAz4!Y{_@9oyP12)JmScczc=6JzM6c=>6!6y5@MbIc|Z7PXbMH+^Etuhxe}lWR=IzJHb6h+UEZ35M%5z*yg#X%eT>3ED>AIyh@-|c+llGM3klhjwm^SqG!rVKrD+vwA+-}v0la4rtmX1h!K5<>vh>d)jA<2Z~gx`I)#)mUCh?fK@ z$;BbNvSvQ^xWAH6(!NMC5GU)LzSG7oZRs5^F)yjPt;ed=(p3BUZjQb!+LD@B)Q9&Z zkVySJ2>j*FA0zuV)bi2BVylp3LDISLwH9}p6|JsGw1-OeA(2|Rzq;}~_w}vxrwp{` zI!_@HyQTef_Rn3sbL#J7XjAdqNKzp2ezzf49w6J=bM2Om;HJ$KDCTU#7C3PoOq`) zYPpFc+Hp0eZ{1ZpwH}8BE6ZXeV$lNb+h@%=ck;fG8ec9$ zB6jm@*r$Z&oZon!TwALt!*{}vWR^Gs>lAx>Kd(Hy!mUGTr)Q9)M-uB%;$FYv*>9`V zklaKfw(h&2NdxPuBit`BTH`Y$nUE}f5<8;pw0s*iiMKqvpS-v3A(7SkE#En?Vj2~v z9B+#v$xfWCg@4U=b;5MxelXUlh$I7&(|3EHzmdJkY83|!8X?Jo#Jzf%8Zo<%%d^MQ zA5e3FN-}uio(va19V;_&kr1b^N-c4Q=uLBH)G_)HY%msyl;=^ZEZu`oy=)X8XC@M{ zLE9A_pX3W|enyi}LuD)p>34$U+XL2sU`zfx!@k&l;%ic)WlP&OZ&}ZkZY=`RoGmf4 zvu;tXJm&4kX{*Q+uaCZd@MF%Mms_mcD{nqZYh;*~5WAUcU|!qi{iwNh%=0miV_qI} z-4^!M+v(QWyUotmc~e!hj&`j#xzf_+y7tq1Bun{cz2?{b!gvM{iMj9eAdd7Qna0KD zdwb!i@q`y~P9c$g^saSP;>yvBWi3Fp`b$Wpou>S`;@!`_oT&Ol8He0QB0c#ht$L5X z^>xlaR2=Hmq*tatc&+l8J1vD@p3P%^Q*mggCR(GLNjpUYbBVd#%;T6?l-6jHT3Oyu zPC&n7((18+`8CVjL(KY7-+x*^nvnAR&s)@71M?PaUO(okna?E5N2*SHOYItL(u>g+ z%tt7HuWkuR&1}w8`Xe(VlYIO>cEvCsL7JrY(cZ-*4z1q&x?s|a(Y8aPtn%qiOUA4H zcbpC=FHc#^xR*ZBBp*s@?mOl_djE61zh0B_Vp#034YHOd`Ou3w^{W5m8eDgXe%-de zUHCQrG27*;X<|3DHqXaIH&Qd7%Q&qCZJcPL0X3Hp4NOwQqE0oyOU+hSWC&^Q zi6-M-Y|vnYJ_pQMXK=6E=M(Ynm@%p`8Hb>o`S`%x)+TXC&BPDP#}ps!-^^##Cbs^l z@BHP|5~!Q`+LMXaAMGieUrVG*a_Xbn?8Bty=#|aaHcZwWs8e&T%~Sh+ls;B2WR1z+ zw5NR*o+xW5c>GZ$?sQBGemqe0>365JFMjCDlh={R+<9)nWd+k5eA9tAvZ_lQ$M?5c zb!WWJ?-qna@#G|aS3JWXD|Qq~PaKh8QOCEMdFxMWa|zKc?`VB(BdqAlM_xyY^&=no zLI&3HLn13Bho>|g_IkEQIwa~%=;}yhMJ8phZUcY(>1_!mp)Hteu;2?lwR-p0E$Dc6 z39Dc7NIgp%&f>^*4jZ%^qp$D0ta_kv&zvK88kH3p?VEm%sUgvlbCekQ_=k!;xe63- zboBUzV)EXUJc~m<=1&W!8mnty`F#7*19j~3=A*pLN}S9{WL<1wtA)#^9c~|hgiou8 zBtH_d&hjtj4gWm#pMgkZ28P7^jb6uhS$CzZzQv)wk$XIkF= z_VN&^$x1yo2(j60Wy|?!#~+kNRXS(ypCetz2ep*4BlpBS<#^^DXqh#wTc`bA9r zVzSn$`h$%V^_De0#pSZ8!(!apm`29`vt0XHoq73yyCONO7nhC(n8F z8FqOJ#K&rj(!TwC{@%S~Gp^K}n8@uS>5FeVKHn=J9-}x;zTH$#cisejf5%+w8(-4P zqRHd>jXNz%RdvXx*g*f{;VUH4TYgi1a%A&tPv*o+(tf3{TVA+3a!P?oOOM7&3L}x! zX0N;&`m$@QMe&jeV~1=DoOxH?QvLHkg{?yyq*ou zr8PDrB8oH0t$8zH|G{a0YUR-!&ZLJ$1E=4&^pY2k91tw z_$phuSK#qe)+d+Gx(!7)U#@eEt3tw~-xyvI>7_XXxBps5Yt)>^<(fynAaVBgns!sf>Dz1CEpaEQ4Nw;o$LC>@XzK@#x@mDx&QZ7jJT=ESqJWgg z@mV(dH|^tR!)EGz;xo^psb4P$e2s_501m%)d=gXZ#nA05;)suS+f`t4uS;k06G!eD z5yu)87cL)A%)F`j%KXbO6hR@|3y!onF{3 z;91uD^@t;N%4gn8egOgvoPN_nn@LPZ1L-Md`vo-lc5k<6Ej8`S@>h{a@ACLjp&j#m z{Eli`OIKyNk3>c_^S^zU;#HrspJ{QlaaF;&dTK4+HT|S|>fDU|89iwY)!I9Xo`kOk zEggB^r(g-Wldrz)8^Bw$p|+@~(ND_G`lNQiE-enM21{l4<_-OZt(=QQ8aK6Fi8!KLy1grp?|CzYaW5M1do}!KArdL+_-S>6 zpX6A^C~bhe*+87;D$ei`Gp2rdD`E~38TaD8U66kNOEyaV}hJ z9DE}~u_2m7vq4By6rHR!%wyGk|1N{Geu)H^l6?9QCnKrl*q*xbgJ%P{D^EVU$0HHH zF6H*+l+K5(&ydI{+N-=}ijr(-)h^4^%4xsXQq#U0J`aglr)Y(><$AU1hy<_Fdh(u8 z7VR%f?2w?aSx>3C0rG$q8aTdNp^fm7IC>%)Xk(W(I0{ty}_APw;<_G!C57T3<78Wkh=Ou;n|GaSL;>vQZmn$H; zb&rbV!-DkYHT{n-&pu1P&S~9cR8(+e59~8P^7c%xRL`TdIJ%EUh2tlDU8PU*hHYb( zF`uL6w3SoyeB{@E1p9hx$f+d3`n`9}d%M}9Bdt+Ume`vE_C9#G5wF5-TKjSQIvzEr zd2jb9|8UWud|bAT*N)9%7OMFU<#Bv!TqH8&;zPL13jD)UFL{3N`txixR2)j;xlpgU zREfSjZ||^pO}up+Qxn~Ibqc$gY2Z|A&EL$eV=i$_P4jq4>KI2=sl{`#-b#Fbj#`$u zm;4TgTxE!2DThSnr;lFso>OjE1Y;z5{Zu6U&=Oy3;a&KZ(#bo^$MBt4 zQWKBgFk;@O+7TlcOB}6woM=EC%@dvcqLTJ2Sw1|@uWRkoYD>tOy?uf%B6(ZtEYt+`1fkjT{x-E6V804w(E->zM*uFt;AsU-9i z>xd(^ZaN@z+vRW9u0TTTkvL9%-9`F0Bs-J_i@u(HKXKl!#xq&?=n*8+E1zv#XUV`vhZjStCaUD@rrlJsihooj5r#g3oQm4<_Q&Rxk|R+=$jBJ|Q>%5p+m-n9>FcfWl7}mFTNiO#Sf|hW zDo>D5J7NQqZ;4_9rxMK%oNAz@)_0{|bJa5aG_}HxWbb)Z@8A#~s==~hsycVf%lPs*`3^cgyp+euxJnis@DL|! zY3j<A)Vc$HQjd#rqbh~M}u znKAL`(v@Z*@zXmICr`bq@;F(uQ!8fC!S;xlZowA6acQm$yO~2~U^3dE1v~lWGqpPD zD3E_#_$ieZ8p<3_4l%G1a2il@7S98DW6vTUjU8sJyYg2CY)M`Py z2G>NA0uT9NSKyd-!!LJ2qNbFMRGgEunkGqkF|-O2WoyE{ zB{f>G$#?gWv?aCl5xW^yi-`!$q^8M2BRqoXP zner%!lhtFTfzvwGt_!BE-q++e-muQ;je4u^bnarr%vx^x7Z0`Bp~*MEskz<}_CWdl zs1_+QmZ_idN)TErf4i(w%W<|(={9k`CHW4Z)Q_*(cecyW?Ca0fHHe>m7+#flvwqzk zwBKMv@Ilr`?N>ecs^p+;sonM|U8}i6r%mKJIhIpPh;6 zh7BBlMMk}RV{v>#%#aLW9+Mjl;@|o+B#!SU84}0$rVL5iZTfor%)OCy>)O9yPHRXU zSDX!r!eEY_bIKI6m65PPjLuqh6F#3Ue`m>Drj5v<(jv10c zs-*8Kmb|$Yus!{_Z@g!RosW;>=vA~Itq*bZ5JTcvr-sC_ehi7D z4Gf86n=>SiZO)K5wmC!M*nSL2LQ3k`7L3#!+kzo+Yzu}YA$D{0UL!R}Pc$TsUS&ue z{lJizTgP1Mgw&6DKIXPgh(#Uy5Tm5#K5A}jbMG~`wd0*)HLS8Yeq~f7(oW5-8YumgQoZ3K}&p90lX$$26{<7xIx=4}FQ!K8rhq1r$#DJ4on_4wApS79)rl9Fs zfR~e%67@@a(N_OZSp}UHQK#j}3So?uS;f)rNSpsQp2>WU8Gm>Lzl0TSvj<=Q{8Yf$ zW64PEHY-GbgnmPmYj} zlUh)7=R3RgCm@zi$?E=Oa9DB8I$9j_`f>6VB(=t6vLeI9-h3u*^7KrZkNx(i^$fxZIxSAMU+9vUgm`{8d7e6+Tmwi0a((tOp!$x~Fc9#PxWugjbKt}k`!{5Rg@ zHp23~`m<~g7By{{KK6_}@u}7=_aTvW@^|Tj8xAe>wki_!;D!_3Sm6@iNr-Na-i!0n zPArz$`}7(A)2KUNueRM`g^BWOb7#lrM`gWAX4PwnlL4*Qt=-YEaM8>gG_5rs-KQi! ze|_xTu9rctkf?$0IV5tQsZNo!2kzBvAa^)q-5(81EQ%y1Jjlim+*mqHdNOp>@$S=! zqki+m>C>oM&u8*9D!$|7Z6dXvICa0?=6tFj@(G&c`A#d3W`w0kYx zrRk>Cf|Jx3;>$9d6N%gv!PZXO&p-7l6LwIqg`OoxKg@qM!x_rMuT_i3|FfQcX!akL6p30bvc*PngD}eC(cp*LJv}3G zBjIW$t54_9P1e$CM`p}%=yq%A-{hVi{$|#Td3%LL*t=PI3gc{CM3EvV2BaVkt}Eq< z2vu{X7%>{>2h`E-@7cFwe)lJWl%^&Ew;a>wU=a@k^eaIkEk|YFYF< zLy<_&7t*lk%GI~~$df(NPPs!k1xZ>Y=guwM(`H2){o7hvYVv!OJiBO#Tlg$;c$1B% zl#lXk(PHAr9RZ(*ErXKO>LK4c(z`0l79^RG44remaM~Sxq;1RHa$432Bq@-1v}u#N z!{iD(RBH4PnNR3#;X6Q1x0H>F`G;TS=_b|hI9@enP*a}% z&GENpwK!O(F{#Nlt6Xi{eE(0f@SYwLt-o%k^4aS3^YwH!l5xctpxUX;<`EQPkBUw= zK5oRAP7invl7=mvi__mS)r#Zfc}q1daiRhBqiOKwv_1|=T;A{CPaRhG!ERDgwEpml zA-~Km13S;s=DJw}0&J1dQI<11lh*q6#U{qrlt+6@;m{devhYenrnQeRkK+|x zyP#8Z=ZGU-b){zY%U7Dc{6E94(*V+sj{1|JZ1giZ$qfZM=gI4 zCmnHSY%8&`O5C><^eYn=Gbdk#Hm_4<97~cP_1=Ho(x3aJExYPje9fgrBDH<6>cu15 zN6uKMB>1Q;+NzCewsy-FaM*1#vt6viyA6zNi6iCd-l0_c?@xcqojaMAPzjbG#v1Z` z)vKKuM(pbv!98TL0mk{rZzvZgwe+Oc_+qb@;gQ?PN1RIY9fma#fl-!UPNtu*%CE}< zO#^M*>*%AhP$F?6t@bEej6KwzZpX$aFFJC!T&q*cQ+>2PPK<}O;7*F4_5eiCBqgtU6|k~;oEyLL5`Ye^;D5z3;Ur?s4mOwF%F~tF)y-C+i_ue(&QW_nBgX zLL#Vz^yemJpRspPW;KT8s>up^2m(u&fy4GzZhfnoHtyBlmi*(2KED2>OSY$H(ypki z#nG;(iLdHyu2lDWtp<-wb5^BB2N!6wMS9qJh93BH%Kd_+*R9u5)4INN#F5p!2H#z% znE2TSS%Z{Lp5aDlL`1+c6KcvZK&$_ z%>-?<&aA*BABGzyad3H)IOz8HCw-i_{npv7&6duRSpoTr+Miz2$9ye6jfg#;A)7uA z)+FvqvZ-+2u<|b}=(7(^;$&u|E_CLpB_vKlG%#OFGjEON&pCX!#wAY_QpNmDIQWUa zJ*;n2REn|(c=ASbv^6x;Q(vLi@=%P((KNFQ57P|3XI^0KVf zjk{G00_7Lh0<_e2zH(n=|7wCeYec0aEbY|=l^*8mxg|P^?uS=rI-SltxOvcL&mXIm zqM_x=9C3?H^ER4y9U}s5mZ5F^g3=$j+PQoo-Lofe$h9W(h&6?3spGiK8;UkN^5}dM zj?>Ecw?>;|_TA;jcUJOp$;;25zr40*h?1|l(mP}IS~(8JaxClKq4_6d9ve1@$1>|&cIx5mm0gPOT*YxFj*r~=X?NdlUmn`Sv8?vD3~Jdi#n5%T zk8mts02nxPlV&a3MV;`bWT&qW z=YBkH8*&*vU%$7{8a5*9{ttf*9s6m&i(2B_iBnJv0Q!e-NIn zL;c9^uAQpNy2`5Q>9u7F^7JRj6!2sUkRe}|ESVDUQ>ft~B58|rN-~IQ$`Okm-@Nf42 zoA^H>{_p?szx(_D`k(%b=l>F==;MF*dnO0}@Gq}FAugk|yep*TcfY&u*)-j?=eJ+( z8lB_6Kb_Za@eF>t?@v#=N0@hy5Bgm<3}L`Q^Ka<6{jNLG9%p*} zuUZW3PR)wz4=$XXZEOb|k%cMk64U|C~&oVC?BH4 z5Sn4r?YS$KE=GT~y3TOD0Z>B_=E@FTuh0x-pqNRurt;V`S9j3OCDUlW98OpZs!0mnQx;q5 zC@n2&diCk1Jv zIcOQp>dKMgOZT}wj!77DE9moVpwFXe)~dm81hqjFHD$w^u++5sGt^5@RzC*0!$I0b z1=CD!P|u{M5wC)6@C*aR5KJ^y;C9CyAp9ja+Zaw`XO#sii=l+XK2a%aWOiybu*{?; zb@2X#9{HC4G;KUoaF-cDJHWs_{iCHqmZ0Ii!7qX-@w8uUP`<5<_QDCp&u=y>wx#xM z$kxa#QIpm@8-?ak7|K5zXgK70=^AzBN)1vb5T%HN2Tc3j=h_sJXQO&~bdfGu z5&(uWVG)j;Y%t`}MeqejKv2Z34_afP(`-IB%!5?2+kauPu|L)NSDr1fW`wei;muBC zc>s@LhL<>xh{{)1t*NmAO_4>D#Es;D;wBBI_$ug(Sb}RNHE9EP{Kl^T{AL0cx6 zp5%4Nn|=hEo3ut&M_q@bL0DS>edw8%u|cU?9WT3$4MahmN@+*>pe?zZ`m|o;gN7n* z+K(qGW#wS?}|R7vd@FKr@#twJr>t z6>2K2^g3GIUqO8}wQ5am)q@*ua@XQYJ17SAaC))v6`nG3OL@5x*c2k>yr&+-` zOj8&84C(4-bs@4@_XUU$NIFfW zjFAq&#;{ETpH$jf+E9brtIQVF)yX6$=q4$N)$7$>iojNu)G7nYj6zvJE~?<*LJ9N` zG)lZ4xjR0vjqxO{Y6x0+#+C|0vo;1aiy5@ngrj{`u!F4?$Y>|3l$#l8fz4uwAA5Cb z%-!MCoiEr;a4WKoU@J1a`AKt+%|9C!YPFGI%uOLvj+6m>wU_n4)Z~4`A(=_SmekAv0pxJ!_cuj$BfWeVXBGe?1&)+WJjiD7Z<3%X0Oo zcd;r-V6Fa+-1!5C)s7wqvLR^gZwoaBOWU^C^|f&$%LSG!W(IL@#=L0;aHKY27P^a; zy_oTdUSd7v#2$ee6>CkAGJ!Tl7IltkfnXR5pP{SWvjl0($$xdhyt>A00X}3pi-97}QAfuh$}&tx;KIDhIxZ zQ$80BEy5sM_Xs{3zCGAM1Yegea6Y~MtHjjKH`FVckJKQ{qcAB>28@gdbaUvoS6fiq z`cFpjiX08AMr8wW9$h5cMVTNd;@0}sej5z5+5)U~urUv4#xS*$C8o}uabr@D!zQJc zQgLgoQvb4VO5yjc@MTA%#4JmJ3H=u{$B5q3o2prZ1Miyfr_v^~qaew|GKnqY} zzR~OOIPJ|~Op-;3CNYJ?W;lF7v|Ad+G7jlfI3DtsJ2=oZmrSkHBK5|9od~eL{v+eC zFIcZ^k%O34VB-k_c_G8ZGddD9*lKJ>ZlWVWg%irUm3kfmp$+eTHqLf~2Sf5@Xhz?K zX1)HfY1`FSdmcRJjzYR^zt&esbM6wVM{t~=?DrZfVf8(pKuvdIZMf?Xbf@U~pky}N zu(tlf((vt?rO)-SZqN6}4qpJHa&=)vfIy$OPpeB4@|PYB!*ACU7E-)03!+j{xo3y@ zeDu#7C}DInRZu5mVOj89pc4c`V=zF+u%wB-YI8|44z0UR`BtYomm+~MW+2rDXOqDR z2UhFd{Q)oj!>a%MRy^Z{hvs_O?Qb|@oM^8Hw1)M*+kAF2m?^!MOM_f@tmQx)Yd@d& zr`peQ>y@pEO{m)j&Z>jz($?@?zSe&An8k$td0)jpQ^_P4c%!}i3jO%E<7I=LYuiR+ zjh)$#;c=sJ_4tSmM!my&!qkwU(tzNL++m*jq3X@%{BpW<2=VFZWk{rXkqPr^{Gq`^ z?%mz)aJbsQcsSy=z-wEVzPp}TKOa`7W|%fEY}?7X2=@vbQ)KfPoZu>hM_QaAtSN%x zCno~>u?-F&L*S#&T(f!J4yg)fzqI{f{DpA#OK%In@y8I&euwm9e_|V`>5luCG2fUR zvd&^@I3;!FuIEcDQfhS#K7Xoc2x)HTK)wxE8#WFuT8}V{PMLczrzN>5S?j<1VG_Ta z#6L{ppH>Vy$L1NeeS@6_(TH33ht=mOCSQI+Rp(qP^$#}M{ce4);p%zSAEJm!@+!5< za#2GY;)Z9JRKW`5%MpN=qv=TAG&x5o&~wS)^OcFj0_fUM3iF+RBCwFh_tB)M+IuE?T7~! zBDLN+I!Bq&2f8d~gN4`Op0&Jq?pe!x3{?-CGMcb?+o<_zFru`>c>h+9##CynpFycl z>O-~s$L($-cZ+Z_60_Q!td>$wrP8y)c)Py#>#nxYnB)Xm05Q$qlV)aWvnJRV5%32@ zbf$75r@)&uFfmkFU(lT0Jm4T(VZ)dQTw@p()i4X`1o(!?^zwcP|6tJk#j z^-@!zcyH&tl1dQ*^l-n2TD~X)G6en8>9Hw1{4Ec5rGHvU;N}(oJmI)jwV$$`aS9m;F zs?uW+HpdemDl_hu>G;MM{OqdTDx5e4RR|aXUVA0Pz@-Q>#kPkjuz&T>elOeG-S7YM z_wW0aTn@qnP~k|P4YYaGW^+#zvWf$q#ej~Z4QqSzB-Aw9JzTo9IaHx5&j#W=YRvLF zk?btj9w#5_6oW>Q3s(>;=pw;H+iNIYQ39ksi3^pw+Tm;f?7L{ZI%)U;!oJJw+ocT# z*ojrf%C(wp_U($308+YS{bb*R*}ksw7x}2h`TvvfC}5E>vQ)kYct2#y6a`%JvRNzVcqR@RB{)5zJ6JKSp_4DTyxv= zsq6MHtakfoRSIGHvDug^Z+4 zOqfIDVX6Hw1VXduaGE4&w`jc;PQ1MP$xKFkjB}n7`wec$xkB-2q3{OS)DZH58OrRLDTS|w?aKz*{HY+gd-v5xMp3-<6|~@1DnOnE@?8wfOtKkI^p&d zo4u{sR_3yUdM+6)%pYE#)V-eMVd!sU$G5)#h#}*F)qa)B?4 zEgGn^;(*R#Ng8Wq$M?uoa15rJ)Zy4C)ocWqLP)pFJfYDnAgne4RLk>5e3?p61auLS)b&c%+uO8Ph8)&UFkUC5QM#Qwq+${jnuf8J!Nhz7T})+0u$2jEmZCL+4@bSVLmu#q`4_1_tK*Ax1OSI1Eb+I%%Eb=Q zWdhTZZ*0oePF6f8?88b5S(k;m-oeM+dSJ&eTjxR38aEx{0#R+5$@Z_Lb_F87ZJlF!P8v0hC39qf9VSus&U~!Mv9`+&|>S zq%TYHNe=3l+ z%^Ue|_1Gnbh)m0*z$|9%>6MvjxIkwy>+CM{jK->gWdYnoW7UA_L&=3oS}tGfyBu=pZaUdL`0xEQe-k6j^gyqQ~OodB0cQBw%f2uPbn3yOtVtJG-*+TF}tVoTA79? zDT}b+g28#Ao%UykAPX>^Mi5I6t4*^#uOGvbS*QGWn`R|5=A}pq?se8^HO=o;7)pQj zH>-xL0@#|qAaIH^ki7`oSZ{EQ;boBF#X`Y_5Kww7+>y_7Co2k2=uQe5l-FZRsYX%q zm;XbLEc_uUb~fFF-PRe=kzSi$yfx!UvLFZYZJhTc zF)#_R5CA5wL@@5PhwZyhKh!Gxv_iL0nHFGhqglNYN5sI5;Y>r(g*R*L{*`hitd<89 zW7tUdgm4(RX=Y%vSQ7lr?t~}0N5TLKB^e^owZyJ<*nSL*3jttcc&PWfj4qX!s5IH~ zRJBpifgQteeZjhuE)s!E7QOaW+ci2)7y>4R=J{V~(6UnsHf%}7UYd9seR;li=l09# zk7oJR$-3I6M41uXWrA_f>tCr@(RO{%t}-+%gWcoJYrSM0LRK4(i_>9?a>wDpn!$4s zDh5HIr~SLq8WHqnz}9W%bs3!=;J( zu|3~DCm5pvsIZK&9mLj%Q=ZRZ*)Caf_Fp2SC3N8a`+=k|%;VOI{K!eDIF0C7C zz6CV2JLN_R$iN5mak;vHkeCx}F_d9j0FFEY%HMATlSl)n&qBcIxzL+~d7!&VqcsO5 zz=h|+x$`s5MyvDT(+8&5@)+tZYVy9n3%Q#^|7EiPgo)z%HG**7^&24$*Z%e}=xcQC zRuH$4tXT1{-%xGxF2x=yEr4&SvK6qb!rV90uKR5RNKIh<7R?aN3RCub60AS3$iy7A z?rf=LmfyZ$TE!`s9KThuq0F3|7z)+2`8_t$G$@5zkoewjP zSlM9LDAWIo!t0_H%KpuTD^`gSxx(|5>9?wPK6}g-oM-sHLWfl~*8VTLU8RWI-k4_< zx|wk@6jEYJq)KUi9(I@Ufq2Wl#+yy`Y;~=Kuq%=kNdmLKzwcN>da;|VqP+pmT)zI< zD0R|XyZy^vU^^cW5$IFSjTX<_S0J*&zA+BN$IQ@ zu@ZYrnan*B6j_Ys@QseO7S>UQ;r57mTYk&*aMKISiKqIe zIkviFy`QAoUdSYkLwF2{_@GYGB{h?z;0MMI=_DNwa$VA6lk|8y6DB0CI^=z&DdONj zRqdN4rU*cdV<^?S)=x?#fktqI!1tgSIR%z6{5^=qi>p91hQABZ3$9~AqVM-0NR0%R z6!{)hqi}#}41W(I2_86X)OuCC*N6g-p{Z{lZ$wWUG4*wQDH|cb_-KINLo{x5>TlqP zp@d}8FVJ6?OKs48gUTB_`f^|nt>;V-WYi7)I|)O<`Q)w==BiyhFtT5x;; zV>)C|jbl%9%L{u_-g8@X6u-?3Ie-`e-f%qu&WQj^9(}bw5>MT%THk%16qEr`P8LhW zRD@t~c>;6@n)j2d+?0J{XbI2^!9`4aY4LLf$i7UA{te-iGloAhqj|RU{2-&s$_|+} z+$0jsw-qMYAv_@M%SkqweCrz*bS2!G?RIG3vKadwzVB_!Kj?>f)b`fgg;I9apo-6; z#^aB+U1gU(zM+#{I&Brakw@vCt7oh;?(g{!5ES{qQ^d6s=8Euy8=*2ef2<D1xENP>Z-iGoJ30|V>xHd5-JFf^$)^|(@1ZR+(sY%w&ib!!ao5Y^m)n~kPqqtC`6WuDtm}>eEe1m%^ z^G~?dJL87#+wRTS5=cdt<(Q-;gws7bj}S`Epy1qLHnBaLtMKvhCiCii$>@%4U!z>Z;~*B~{l41-4;=_*Y=lN+=%sYaSLeH_Vb7#K#EN(qs@ zno^5Fh+8V6|PAE`; zuCse=!lXe$IBXe}HR53qst_^eq2MuWg?Wn(<+f=&LR#1$y}k@&L1#cvBrU~LG9Vx- z)4=3wbWjv{8ZiVrtJG1C3+m0W{ejJ5Rs*j)=K>$5NRZqn8ZOVPjXGqIp(0s=@gY2t zSrLaEz_i9Nl~1V3e);BVX1eGc*1!eB>P>$7kjZa>ezEQ7-@^h8jFnQg3*Bgit5P-Em<{1p;m41-S{{SWN ze!fD1(fnEI=r?&)$y|xDCu~HnRdUd+IONBp>F(q_mz@IUk|AIF&2`Z&7DXT`;_MCi zp0}~H#P!yQf@P&Gz|@@ny#R<&T)u%IMF95g7G$4UCk8w-KNwDrE#NHHq5)fxWcHB- zc*gZ@z%fRR4sT?Ejv(H_L=aHqDQOF{B9g^oTsYzb9JV+&I)bW?QCp97@Wy2Av~Qnf z16dw5T;6n=3<^M}$f9ZdSl7Zce3$YT@<9R`~p`0ILpNT0=7vCSmL}y zBO?{O(_n_cT00gQL0LjtZM`uNDl{6E>+;*gMbe#QIn!GpYc}1eb5~A!syf)jk`?3@ z<2UFs87+e*Gfgteyq;*CZr;2HeU)DgyEjf0UAk1{Ui)bg)x6?r{#W*G?6O;{sGfK2 zj-0Iv-dLP=i17zKpkdF?rnG)_;Qtl58kr$zaGn;v*>^`fGNSJyh_WJ(Stb|`k83$& zz>r6oYvP+hl?G2Nj?jVM2)lGd`U;)~-1~$AW9?AERAvNQnUFAQpJ27ut>iUH%yNM% zi&;PPEH*TOMq40b$Ocfa^M{AtAGBFF1Yu%iM5XF$`6aLSrq_E7Hfo$90A2AoZ1e}I zIxp|qw*B$r2TF?}WW*n&N6ex!c%9&?sU?UvJKK4`2faTBXo|p;=pgdU%XiN_19z@z zwkZ=>QiQ6BS%ZrBk(V_6I#S?~QPU+ht|{1l=1^rI~!#-EzLH2qug<_sEe=4s!GZ=@%+#(;L_r|-rdPCedW z4$0q&b#h#6z&c6(R;;1A!+FaAX_@-{IKvSz6Rm_&XTDN@T_jhj%MKK#lyAiq7?vGE z%p`wEU5fMcv^#!n@CwnQG@WV2{`Vo=9df@qoVeff$}RJn;pHEgKZmQ6MqH+N<4r%j z7t4&zr8woYw+DO3l&kaF_FrjQeTQv?A%Ayy!3wtBw`(3{2zivHs`2F6U~C>`#>Nn9 zQx6+jVKm{s-mI9T1ul<5tna=1eOKwAHF86x zZvRddq!kue?dGoA320`n;gLq`S$2loaCDOnh=v<=7A){z*J8e*%=|ta-;?B3^=E;xwyPbafk* zyb5{h6VMn^AB^jeXtUvzT8DdSd+Dx^Pb{psSiWW{$+LkrkJ_TvdIpQU@VHJz2*x~M z8N)DzrKSlM&jZ*qg_ta9wfM9Oj$J%HS;1Q519K5KmU|LkmJ5n9fd#E^V#_b*RrRtP zer+o9XgJv+N&Z5y4lUOkS#`wp5^JklobKNI^izHSYEB7e4A%w1(L+Yp+-X-CD@bs1>buo7Jo$da zMNFtyNEZv;=gU?5TA|1{$nx=9o<`OC2_7Tz0^mj-h3)=rS-CI^KI;*%)L&!&Nvq{Q z^>(hon;|B=0dSH+iT>!6cnyLSp|-x*q!t4-IeGv16df0&e3@y#b( z=a0c@ZMPM~;G*V?F#1@2Pi)xNIMFWDE`|)svlC}631k*qBrw`g(SLvrLEskLOt$Ke z@2tGzJIK6qFLC^Zldd}*iVpz_i6`vY^3zYp%R}gHTpfH^RRjS+$DK7%(JPN$;k&;!>SfT04Dhv<(d8C*IfiL2=JrIUR zX3K!J!Ue&GOc7C}W63_(I4=V_h8dszWyEB*2Y!-bT(q6VZM$E+jCw((CS^uYmI;Q@ zo1s_z%aKX(RjjUnE8_*E2rL#Ad=?O>9e`%x`f|Rx3@^7@R z52_*`*s=^DsA&Nzgel8kp7RuT^p%OBv=-u`XwuG9fqGyl+VWK95UsTHBqtP2Qo>Gv zqm;H^dHWJr``XGNj2&kj;@O{FJs+R0Xog`D-D{^d%;lJE9(ml&l+@$t(44PFd%KDh zp6ug1ANzsF_89|QZIv>U8(L;k=}mD|t8gTz12lOwak~O<-Vz*u0(J-@e+Y)d!<-ku z=FvrTk4y!43>&0Za?v(G7jcQSOS`#)St|mbB8;BCmUz0_8}a%i6PH|eyN4(l6=oOt zD7%P5x~`n5ucxqJ3^EFQ7PG5TOtEJ>Yt5@wXmj@Lw(WP?*@m#LN%0DymY)K`nFw*k z8;|hr`Kpa-`!14z37x=BQWBQo2lK?OkX_`<5E@)+t_p@?TmnN8hai8md1AT%$0WtN zrRO-aOBX;7L0h_6GsxS)d_pu|oXrbiyTiTVaK%qB3{M)GY!<83_40JqDiR7~i2A(` zue(&B!a$|#hQ(kT`RwlDC7s7IT4Mm4A~pnj-Cji@)q^ig9))hd(2-*K~K50pEGDapTn zI1?&hvluFXlz@7<54%SUG}2OHXi@DZat-t(#il4vp~G4EjDH)@F|f+ zzJtnZPDo3PC8d`UMVASSxOVF;q=DO$Pi!Q-=2LnLjV6MM1X`bX<^FNGQn;J6FDsJOV3fC$v3tWSB%btl^Q0YrO*^XxAT`vnd}QV z^#tnc&u=!{3r@>eAmkLp*evT@+ODopo-%5kzGI7=3g5XoLZL3@?)P`@Zn5;KC1llFhKt#W399 zjv!BG<%%7ij@2R{hUnY=JW%>vFdfVk|A8$7Z_}d06Fe-;cLRE|n2C>>$PT+l9)smz z&99ASZdk6HcDB53r?5vM7b1Cx>n7B6uVx~z@bQkU5B`kj1 zED+^TvmP)dfqeG!Qnu+;XnJL@J4`ZjEbwlc6mO53B+HFtiZW0&$*93g&k|MzCopZO;s^pe$FOnK zo4clE8=Hj10^froun80)@I5F@VTdgTqCC0?-PGfEiGnm?M34*$k8gI3Hzn43bJ-{o z4G`$Fi0TOiL6$)f0^ftex(*oZ`#lIuW5kd;F&Bde`Yyjga$ww*71 zI2GmV1;;LU^HJasT(lB;b#Az!9KA{lkGdg%CeCLbkW5m{2;?>WxeX5*+ZU~5*uDVw z@z?frYO%eKbFIyIHlH(hYAydQ6L&FfLTwR8jPTerEdnd+iEGFjb|SqaA2yVj&!u^A zf^?F?8p=OWKP?b6(p{e{EA4@ITR8F_6<_*sx?^a=g zq`72T@ME-ntq!YS*@NA5+&hYcE9cjb7kqqK--M-<$y#NK$Z}Cw7L$~?{o+QVeK*6` z30C>9)&{8nw>9&j$SQ}k0 zyfF{djA0uiJX6$dd7!vWTr_+|f})*CW{Tpo8lP4N+bEYnEudoGiF zdT}vLPkU*RSf4uz%wy3QMf?Vx))#2=4k;NT23WFruE$4mD_wr%+6~ZvKSudoTE`tUth#oUaYb~CX@N%&;G0I{2Bj4FA!riijU2ts z1lfws0_urwWwo^*eDPz*I+{ty_IlcL;QOKWF7}uQTF0;{w_$hQWJLEkKh%81gD8b; zAj+f0c~9Mzcw^gW&j62MO~U@^;NfjcnO%T3e*qNApJ^sP4{Nn>@nU?Yb*9 z;abpcRny+L9aUhw*l7HEUY&Kxe&~i59Pc^)W=FlxJr7TBKF2*c)V{F8x5cR*Es!f7 zYd5{5Owg4g2<)J0+m;>|OVuYSZd=x6${>j$6ZxRJR>sk=-4d_^n@0_SXE&R#Ihf{u zpilevRL*f2jC090IC(Tq8c?XpCS6q18OZ?COe!OWzw?xd+<+wrAT{ze304@7E4!=0 z0?SHJSlh;Sevo9rmVzE$%IA||{XSg)yds34)2~3I@tVh|5$^(*_RK~w} zj73MLzO43FTwORKTYU;;nibU3B&hWDnp&&*J}$8~S-pUXtF>^$mIfkjU6B2cNv=WX z;jUxu&gUNZn4~EyzHO}&5_T|20Na)dg;BJ5x*YcACK~ov&%tYQxK5wT^6AWaM4Xp# zu(acA8u$kbx%^SD@a;BXQZ>Lz2l%o&%cD~t6F*PrGpuR>X}wJ#PU}xkL{#-=CwYt^ z%49||OXi{7?pEfiQF{?5%LSG!hIZ(8x|~0N=TX((AA`_D?K)QZV^Uq;RF$_5CFW5| z)S&5f-f*jrolg?4ybjEh$aX%%zK|Gi9<4|K_p@j`(FclTD6UhKNvOd3&5AaayaMg( zjH93nb`W}l^dt}AznnV>YYZ9xJbqZepkDzt1cCFdZP`*w)vB{3bw(94_DmZ!O&4bC z6-8=`grC%9>kFVU56H$aMC+(*osO{>AjdF5;E#&sRd~iMmbe%>!u0Vj=`V5eJ2@FV=F$K^pMos;RHk|DoIShtLit)>v+1QcT$#!60Abf>oa=i|)W*4H* z$AKfu5O&bGO($K+qYn1ulcOf`PWLc;kx=LJ diff --git a/foundry.toml b/foundry.toml index 1b992dd45..a25d34d66 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,13 +2,10 @@ auto_detect_solc = false bytecode_hash = "none" emv_version = "paris" - extra_output = ["storageLayout"] fs_permissions = [ - { access = "read", path = "./out" }, { access = "read", path = "./out-optimized"}, { access = "read", path = "package.json"}, - { access = "read-write", path = "./benchmark/results"}, - { access = "read-write", path = "./cache" } + { access = "read-write", path = "./benchmark/results"} ] gas_reports = [ "SablierV2LockupDynamic", diff --git a/package.json b/package.json index c7d96d64c..841cfd588 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "@prb/math": "github:PaulRBerg/prb-math#16419e5" }, "devDependencies": { - "@sphinx-labs/plugins": "^0.31.9", "forge-std": "github:foundry-rs/forge-std#v1.8.1", "prettier": "^2.8.8", "solady": "0.0.129", diff --git a/remappings.txt b/remappings.txt index 83d4faffa..8f1a7a740 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,6 +1,5 @@ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @prb/math/=node_modules/@prb/math/ -@sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry/ forge-std/=node_modules/forge-std/ solady/=node_modules/solady/ solarray/=node_modules/solarray/ diff --git a/script/Base.s.sol b/script/Base.s.sol index b3a7301f8..2097ae5cf 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -3,13 +3,12 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { Sphinx } from "@sphinx-labs/contracts/SphinxPlugin.sol"; import { console2 } from "forge-std/src/console2.sol"; import { Script } from "forge-std/src/Script.sol"; import { stdJson } from "forge-std/src/StdJson.sol"; -contract BaseScript is Script, Sphinx { +contract BaseScript is Script { using Strings for uint256; using stdJson for string; @@ -19,9 +18,6 @@ contract BaseScript is Script, Sphinx { /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; - /// @dev The project name for the Sphinx plugin. - string internal constant TEST_SPHINX_PROJECT_NAME = "test-test"; - /// @dev Needed for the deterministic deployments. bytes32 internal constant ZERO_SALT = bytes32(0); @@ -43,15 +39,11 @@ contract BaseScript is Script, Sphinx { /// @dev Maximum tranche count mapped by the chain Id. mapping(uint256 chainId => uint256 count) internal trancheCountMap; - /// @dev The project name for the Sphinx plugin. - string internal sphinxProjectName; - /// @dev Initializes the transaction broadcaster like this: /// /// - If $EOA is defined, use it. /// - Otherwise, derive the broadcaster address from $MNEMONIC. /// - If $MNEMONIC is not defined, default to a test mnemonic. - /// - If $SPHINX_PROJECT_NAME is not defined, default to a test project name. /// /// The use case for $EOA is to specify the broadcaster key and its address via the command line. constructor() { @@ -62,7 +54,6 @@ contract BaseScript is Script, Sphinx { mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC }); (broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 }); } - sphinxProjectName = vm.envOr({ name: "SPHINX_PROJECT_NAME", defaultValue: TEST_SPHINX_PROJECT_NAME }); // Populate the segment and tranche count map. populateSegmentAndTranchCountMap(); @@ -82,20 +73,6 @@ contract BaseScript is Script, Sphinx { vm.stopBroadcast(); } - /// @dev Configures the Sphinx plugin to manage the deployment of the contracts. - /// Refer to https://github.com/sphinx-labs/sphinx/tree/main/docs. - /// - /// CLI example: - /// bun sphinx propose script/DeployCore.s.sol --networks testnets --sig "runSphinx(address)" $ADMIN - function configureSphinx() public override { - sphinxConfig.mainnets = ["arbitrum", "avalanche", "base", "bnb", "gnosis", "ethereum", "optimism", "polygon"]; - sphinxConfig.orgId = vm.envOr({ name: "SPHINX_ORG_ID", defaultValue: TEST_MNEMONIC }); - sphinxConfig.owners = [broadcaster]; - sphinxConfig.projectName = sphinxProjectName; - sphinxConfig.testnets = ["sepolia"]; - sphinxConfig.threshold = 1; - } - /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: /// https://github.com/Arachnid/deterministic-deployment-proxy /// diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index e98c688fb..d3c059a8b 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -16,7 +16,7 @@ import { BaseScript } from "./Base.s.sol"; /// 4. {SablierV2LockupTranched} contract DeployCore is BaseScript { /// @dev Deploy via Forge. - function runBroadcast(address initialAdmin) + function run(address initialAdmin) public virtual broadcast @@ -26,33 +26,6 @@ contract DeployCore is BaseScript { SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) - { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); - } - - /// @dev Deploy via Sphinx. - function runSphinx(address initialAdmin) - public - virtual - sphinx - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor - ) - { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); - } - - function _run(address initialAdmin) - internal - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor - ) { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 012e1294c..2bdc13422 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -15,7 +15,7 @@ import { BaseScript } from "./Base.s.sol"; /// 3. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor ) @@ -27,37 +27,6 @@ contract DeployCore2 is BaseScript { SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) - { - (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor - ) - public - virtual - sphinx - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) - { - (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor - ) - internal - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) { lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index a20dc6540..145a6d819 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -18,7 +18,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { /// @dev Deploy via Forge. - function runBroadcast(address initialAdmin) + function run(address initialAdmin) public virtual broadcast @@ -28,33 +28,6 @@ contract DeployDeterministicCore is BaseScript { SablierV2LockupTranched lockupTranched, SablierV2NFTDescriptor nftDescriptor ) - { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); - } - - /// @dev Deploy via Sphinx. - function runSphinx(address initialAdmin) - public - virtual - sphinx - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor - ) - { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = _run(initialAdmin); - } - - function _run(address initialAdmin) - internal - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor - ) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 36232a624..d3603f1c8 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -17,7 +17,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor ) @@ -29,37 +29,6 @@ contract DeployDeterministicCore2 is BaseScript { SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched ) - { - (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor - ) - public - virtual - sphinx - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) - { - (lockupDynamic, lockupLinear, lockupTranched) = _run(initialAdmin, nftDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor - ) - internal - returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched - ) { bytes32 salt = constructCreate2Salt(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxSegmentCount); diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 78dfbe962..55dafd211 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -10,7 +10,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -18,29 +18,6 @@ contract DeployDeterministicLockupDynamic is BaseScript { virtual broadcast returns (SablierV2LockupDynamic lockupDynamic) - { - lockupDynamic = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupDynamic lockupDynamic) - { - lockupDynamic = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxSegmentCount); diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index 81ca7ffcb..c3671bd1d 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -10,7 +10,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -18,29 +18,6 @@ contract DeployDeterministicLockupLinear is BaseScript { virtual broadcast returns (SablierV2LockupLinear lockupLinear) - { - lockupLinear = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupLinear lockupLinear) - { - lockupLinear = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupLinear lockupLinear) { bytes32 salt = constructCreate2Salt(); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor); diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index 148a3023f..d3b3485f6 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -10,7 +10,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupTranched is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -18,29 +18,6 @@ contract DeployDeterministicLockupTranched is BaseScript { virtual broadcast returns (SablierV2LockupTranched lockupTranched) - { - lockupTranched = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupTranched lockupTranched) - { - lockupTranched = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxTrancheCount); diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index 6cdde5c09..53252adeb 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -9,16 +9,7 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { /// @dev Deploy via Forge. - function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = _run(); - } - - /// @dev Deploy via Sphinx. - function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = _run(); - } - - function _run() internal returns (SablierV2NFTDescriptor nftDescriptor) { + function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index fca805329..25a77fd98 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -8,7 +8,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupDynamic is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -16,29 +16,6 @@ contract DeployLockupDynamic is BaseScript { virtual broadcast returns (SablierV2LockupDynamic lockupDynamic) - { - lockupDynamic = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupDynamic lockupDynamic) - { - lockupDynamic = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupDynamic lockupDynamic) { lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxSegmentCount); } diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index c7a4bb85c..8f666c70e 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -8,7 +8,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupLinear is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -16,29 +16,6 @@ contract DeployLockupLinear is BaseScript { virtual broadcast returns (SablierV2LockupLinear lockupLinear) - { - lockupLinear = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupLinear lockupLinear) - { - lockupLinear = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupLinear lockupLinear) { lockupLinear = new SablierV2LockupLinear(initialAdmin, initialNFTDescriptor); } diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 520a659ad..08bdfbc65 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -8,7 +8,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployLockupTranched is BaseScript { /// @dev Deploy via Forge. - function runBroadcast( + function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor ) @@ -16,29 +16,6 @@ contract DeployLockupTranched is BaseScript { virtual broadcast returns (SablierV2LockupTranched lockupTranched) - { - lockupTranched = _run(initialAdmin, initialNFTDescriptor); - } - - /// @dev Deploy via Sphinx. - function runSphinx( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - public - virtual - sphinx - returns (SablierV2LockupTranched lockupTranched) - { - lockupTranched = _run(initialAdmin, initialNFTDescriptor); - } - - function _run( - address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor - ) - internal - returns (SablierV2LockupTranched lockupTranched) { lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxTrancheCount); } diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index 32bfeebff..e6ec770f7 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.s.sol @@ -7,16 +7,7 @@ import { BaseScript } from "./Base.s.sol"; contract DeployNFTDescriptor is BaseScript { /// @dev Deploy via Forge. - function runBroadcast() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = _run(); - } - - /// @dev Deploy via Sphinx. - function runSphinx() public virtual sphinx returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = _run(); - } - - function _run() internal returns (SablierV2NFTDescriptor nftDescriptor) { + function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = new SablierV2NFTDescriptor(); } } diff --git a/slither.config.json b/slither.config.json index edcc0bbb4..a42619ece 100644 --- a/slither.config.json +++ b/slither.config.json @@ -4,7 +4,6 @@ "solc_remaps": [ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/", "@prb/math/=node_modules/@prb-math/", - "@sphinx-labs/contracts/=node_modules/@sphinx-labs/contracts/contracts/foundry/", "forge-std/=node_modules/forge-std/", "solady/=node_modules/solady/", "solarray/=node_modules/solarray/" From db52db2d3046a01fd063d0a3e5213825c87c4102 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 16 May 2024 12:38:25 +0100 Subject: [PATCH 099/132] build: update evm version to Shanghai (#927) --- benchmark/results/SablierV2LockupDynamic.md | 54 +++++++++---------- benchmark/results/SablierV2LockupLinear.md | 30 +++++------ benchmark/results/SablierV2LockupTranched.md | 54 +++++++++---------- bun.lockb | Bin 42760 -> 42760 bytes foundry.toml | 2 +- precompiles/Precompiles.sol | 8 +-- 6 files changed, 74 insertions(+), 74 deletions(-) diff --git a/benchmark/results/SablierV2LockupDynamic.md b/benchmark/results/SablierV2LockupDynamic.md index 8d3ed5a05..c2d8538ab 100644 --- a/benchmark/results/SablierV2LockupDynamic.md +++ b/benchmark/results/SablierV2LockupDynamic.md @@ -2,30 +2,30 @@ | Implementation | Gas Usage | | ---------------------------------------------------------- | --------- | -| `burn` | 15704 | -| `cancel` | 71840 | -| `renounce` | 41020 | -| `createWithDurations` (2 segments) (Broker fee set) | 199085 | -| `createWithDurations` (2 segments) (Broker fee not set) | 183577 | -| `createWithTimestamps` (2 segments) (Broker fee set) | 183277 | -| `createWithTimestamps` (2 segments) (Broker fee not set) | 178569 | -| `withdraw` (2 segments) (After End Time) (by Recipient) | 19077 | -| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27735 | -| `withdraw` (2 segments) (After End Time) (by Anyone) | 13973 | -| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27431 | -| `createWithDurations` (10 segments) (Broker fee set) | 390783 | -| `createWithDurations` (10 segments) (Broker fee not set) | 386082 | -| `createWithTimestamps` (10 segments) (Broker fee set) | 380798 | -| `createWithTimestamps` (10 segments) (Broker fee not set) | 376105 | -| `withdraw` (10 segments) (After End Time) (by Recipient) | 14264 | -| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32678 | -| `withdraw` (10 segments) (After End Time) (by Anyone) | 13980 | -| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32374 | -| `createWithDurations` (100 segments) (Broker fee set) | 2705160 | -| `createWithDurations` (100 segments) (Broker fee not set) | 2701423 | -| `createWithTimestamps` (100 segments) (Broker fee set) | 2606849 | -| `createWithTimestamps` (100 segments) (Broker fee not set) | 2603145 | -| `withdraw` (100 segments) (After End Time) (by Recipient) | 14264 | -| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88561 | -| `withdraw` (100 segments) (After End Time) (by Anyone) | 13960 | -| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88257 | +| `burn` | 15675 | +| `cancel` | 71687 | +| `renounce` | 40893 | +| `createWithDurations` (2 segments) (Broker fee set) | 198964 | +| `createWithDurations` (2 segments) (Broker fee not set) | 183487 | +| `createWithTimestamps` (2 segments) (Broker fee set) | 183160 | +| `createWithTimestamps` (2 segments) (Broker fee not set) | 178483 | +| `withdraw` (2 segments) (After End Time) (by Recipient) | 19001 | +| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27557 | +| `withdraw` (2 segments) (After End Time) (by Anyone) | 13904 | +| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27260 | +| `createWithDurations` (10 segments) (Broker fee set) | 390614 | +| `createWithDurations` (10 segments) (Broker fee not set) | 385944 | +| `createWithTimestamps` (10 segments) (Broker fee set) | 380649 | +| `createWithTimestamps` (10 segments) (Broker fee not set) | 375987 | +| `withdraw` (10 segments) (After End Time) (by Recipient) | 14188 | +| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32500 | +| `withdraw` (10 segments) (After End Time) (by Anyone) | 13911 | +| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32203 | +| `createWithDurations` (100 segments) (Broker fee set) | 2704451 | +| `createWithDurations` (100 segments) (Broker fee not set) | 2700745 | +| `createWithTimestamps` (100 segments) (Broker fee set) | 2606340 | +| `createWithTimestamps` (100 segments) (Broker fee not set) | 2602667 | +| `withdraw` (100 segments) (After End Time) (by Recipient) | 14188 | +| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88383 | +| `withdraw` (100 segments) (After End Time) (by Anyone) | 13891 | +| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88086 | diff --git a/benchmark/results/SablierV2LockupLinear.md b/benchmark/results/SablierV2LockupLinear.md index d86e6749c..c1fe26028 100644 --- a/benchmark/results/SablierV2LockupLinear.md +++ b/benchmark/results/SablierV2LockupLinear.md @@ -2,18 +2,18 @@ | Implementation | Gas Usage | | ----------------------------------------------------------- | --------- | -| `burn` | 15695 | -| `cancel` | 54245 | -| `renounce` | 21373 | -| `createWithDurations` (Broker fee set) (cliff not set) | 127827 | -| `createWithDurations` (Broker fee not set) (cliff not set) | 112288 | -| `createWithDurations` (Broker fee set) (cliff set) | 136615 | -| `createWithDurations` (Broker fee not set) (cliff set) | 131874 | -| `createWithTimestamps` (Broker fee set) (cliff not set) | 113929 | -| `createWithTimestamps` (Broker fee not set) (cliff not set) | 109182 | -| `createWithTimestamps` (Broker fee set) (cliff set) | 136217 | -| `createWithTimestamps` (Broker fee not set) (cliff set) | 131472 | -| `withdraw` (After End Time) (by Recipient) | 29618 | -| `withdraw` (Before End Time) (by Recipient) | 19100 | -| `withdraw` (After End Time) (by Anyone) | 24514 | -| `withdraw` (Before End Time) (by Anyone) | 18796 | +| `burn` | 15669 | +| `cancel` | 54116 | +| `renounce` | 21338 | +| `createWithDurations` (Broker fee set) (cliff not set) | 127727 | +| `createWithDurations` (Broker fee not set) (cliff not set) | 112219 | +| `createWithDurations` (Broker fee set) (cliff set) | 136514 | +| `createWithDurations` (Broker fee not set) (cliff set) | 131804 | +| `createWithTimestamps` (Broker fee set) (cliff not set) | 113830 | +| `createWithTimestamps` (Broker fee not set) (cliff not set) | 109114 | +| `createWithTimestamps` (Broker fee set) (cliff set) | 136117 | +| `createWithTimestamps` (Broker fee not set) (cliff set) | 131403 | +| `withdraw` (After End Time) (by Recipient) | 29557 | +| `withdraw` (Before End Time) (by Recipient) | 19032 | +| `withdraw` (After End Time) (by Anyone) | 24460 | +| `withdraw` (Before End Time) (by Anyone) | 18735 | diff --git a/benchmark/results/SablierV2LockupTranched.md b/benchmark/results/SablierV2LockupTranched.md index c26d41a4d..e2f0d3d33 100644 --- a/benchmark/results/SablierV2LockupTranched.md +++ b/benchmark/results/SablierV2LockupTranched.md @@ -2,30 +2,30 @@ | Implementation | Gas Usage | | ---------------------------------------------------------- | --------- | -| `burn` | 15739 | -| `cancel` | 61652 | -| `renounce` | 28759 | -| `createWithDurations` (2 tranches) (Broker fee set) | 198189 | -| `createWithDurations` (2 tranches) (Broker fee not set) | 182679 | -| `createWithTimestamps` (2 tranches) (Broker fee set) | 188124 | -| `createWithTimestamps` (2 tranches) (Broker fee not set) | 182715 | -| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20258 | -| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 15063 | -| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15155 | -| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14759 | -| `createWithDurations` (10 tranches) (Broker fee set) | 385386 | -| `createWithDurations` (10 tranches) (Broker fee not set) | 380684 | -| `createWithTimestamps` (10 tranches) (Broker fee set) | 393864 | -| `createWithTimestamps` (10 tranches) (Broker fee not set) | 388568 | -| `withdraw` (10 tranches) (After End Time) (by Recipient) | 18013 | -| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19946 | -| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17716 | -| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19642 | -| `createWithDurations` (100 tranches) (Broker fee set) | 2646777 | -| `createWithDurations` (100 tranches) (Broker fee not set) | 2642559 | -| `createWithTimestamps` (100 tranches) (Broker fee set) | 2713099 | -| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2709493 | -| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46904 | -| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 75039 | -| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46600 | -| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 74735 | +| `burn` | 15713 | +| `cancel` | 61537 | +| `renounce` | 28738 | +| `createWithDurations` (2 tranches) (Broker fee set) | 198066 | +| `createWithDurations` (2 tranches) (Broker fee not set) | 182587 | +| `createWithTimestamps` (2 tranches) (Broker fee set) | 187974 | +| `createWithTimestamps` (2 tranches) (Broker fee not set) | 182597 | +| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20204 | +| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 15009 | +| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15108 | +| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14712 | +| `createWithDurations` (10 tranches) (Broker fee set) | 385207 | +| `createWithDurations` (10 tranches) (Broker fee not set) | 380536 | +| `createWithTimestamps` (10 tranches) (Broker fee set) | 393650 | +| `createWithTimestamps` (10 tranches) (Broker fee not set) | 388386 | +| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17959 | +| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19892 | +| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17669 | +| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19595 | +| `createWithDurations` (100 tranches) (Broker fee set) | 2645968 | +| `createWithDurations` (100 tranches) (Broker fee not set) | 2641781 | +| `createWithTimestamps` (100 tranches) (Broker fee set) | 2712165 | +| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2708591 | +| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46850 | +| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 74985 | +| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46553 | +| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 74688 | diff --git a/bun.lockb b/bun.lockb index c76cd3c12495a2f5d982a754f3c197ea9b109322..d83cc08be782b9d93f7ed79e875adf2368669288 100755 GIT binary patch delta 721 zcmW;AJ4gZn0LF2Ru!6WY+Z-jRE_>PA-q*{nQaHC8k0wV)M{#mFaFnJSk05Y7nr^(& zQD|{=%kil1zx=+Be>a)yCUc*^>&w|pCYwoDQmy|}t7fylz0vqLz!aTLl@N2LzKcUN zwp2WfFkez>VvL1tl@=yg+)-)c2+duU4vw+Br_#d-R`yl;I7O?hGQb(y2Py%k=p3qq zm^;#UafrsTiiZ*APgI&1W8qY#g$WkVRN6Q~v!c?$F_zC&dN{$#g-Rc%XkDrdaEA7k zN`NUk*D4|AZuDIoqH(L@VT5^0rHL^X?o?WsVDVn1jUzN4R601u@}o)*Cs=t>>Ejfw zs>%RoXg{k2n4)8=gqVBLcX5cutBQva=HFDB7-ONP(!!+H@ViTE{`bPFUs|01dar-f F{{U;f%Sr$M delta 715 zcmW;ADQv<30EOW~mS$pM4%uV|Gsf7(ZrI80!XOlfBvX}0Btc=CAjuT6S+b(dPzuhgvFj7Xcout<5?X+rMJ>N8b(!&^Yhbn!XVc|$+fO9MztBi1g?Iw!x(edDt(+`p{z2%IhHCaBV1tlMrDjktlp|jaE11r z$`liH?p1s=AM`sIVCGS!iy>yKDlSH7J*o6C#@w??A7@y2Q5oPIORp*;TwwW4WsFO# zzN<`dh4zQa6cco86(7x-eg^~0)K$6|V)j$T#R#p2N)O{k+bgyzUU75d_pABc{0Egl B$hQCh diff --git a/foundry.toml b/foundry.toml index a25d34d66..4a8289e4a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,7 +1,7 @@ [profile.default] auto_detect_solc = false bytecode_hash = "none" - emv_version = "paris" + evm_version = "shanghai" fs_permissions = [ { access = "read", path = "./out-optimized"}, { access = "read", path = "package.json"}, diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 0edaf7303..ed7adf5a6 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,13 +26,13 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003dc576001600160401b0390601f601f19620059f23881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003e1565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556155f090816200040282396080518161395e015260a051818181610c050152613a250152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461268e57508063027b67441461266b57806306fdde03146125a5578063081812fc14612587578063095ea7b3146124865780631400ecec146123e15780631c1cdd4c1461237b5780631e99d5691461235d57806323b872dd1461234657806331df3d481461223a57806340e58ee514611f80578063425d30dd14611f2c57806342842e0e14611ef257806342966c6814611d1a5780634426757014611cf35780634857501f14611c7d5780634869e12d14611c415780634cc55e1114611b4657806354c02292146118c157806357404b12146118275780636352211e146117f85780636d0cee75146117f857806370a082311461178757806375829def146116f55780637cad6cd1146115fa5780637de6b1db146113e25780638659c2701461108b578063894e9a0d14610cfe5780638f69b99314610c7b5780639067b67714610c285780639188ec8414610bed57806395d89b4114610add578063a22cb46514610a20578063a80fc071146109cb578063ad35efd414610968578063b256456914610914578063b637b865146108b7578063b88d4fde1461082e578063b8a3be66146107f7578063b971302a146107a5578063bc2be1be14610752578063c156a11d1461060e578063c87b56dd146104f9578063d4dbd20b146104a4578063d511609f14610455578063d975dfed14610408578063e985e9c5146103b1578063ea5ead1914610383578063eac8f5b81461032e578063f590c176146102c9578063f851a440146102a25763fdd46d601461025b57600080fd5b3461029d57606036600319011261029d576102746127bb565b6044356001600160801b038116810361029d5761029b91610293613954565b60043561335b565b005b600080fd5b3461029d57600036600319011261029d5760206001600160a01b0360005416604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060406000205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360016040600020015416604051908152f35b3461029d57604036600319011261029d5761029b6004356103a26127bb565b6103ab826141fa565b91612fa9565b3461029d57604036600319011261029d576103ca6127a5565b6103d26127bb565b906001600160a01b03809116600052600660205260406000209116600052602052602060ff604060002054166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576104446020916141fa565b6001600160801b0360405191168152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060026040600020015460801c604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360036040600020015416604051908152f35b3461029d5760208060031936011261029d5760043590610518826136f1565b5060006001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa91821561060257600092610589575b50610585604051928284938452830190612780565b0390f35b9091503d806000833e61059c8183612942565b810190828183031261029d5780519067ffffffffffffffff821161029d570181601f8201121561029d5780516105d181612964565b926105df6040519485612942565b81845284828401011161029d576105fb9184808501910161275d565b9082610570565b6040513d6000823e3d90fd5b3461029d57604036600319011261029d5760043561062a6127bb565b610632613954565b81600052600960205260ff60016040600020015460a81c161561073b578160005260036020526001600160a01b0380604060002054169182330361071c57610679846141fa565b6001600160801b03811661070b575b50818116156106f3578361069b91613813565b908116806106bb5760248460405190637e27328960e01b82526004820152fd5b82036106c357005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b815260006004820152fd5b610716908486612fa9565b84610688565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460a01c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160a01b0360406000205416604051908152f35b3461029d57602036600319011261029d576004356000526009602052602060ff60016040600020015460a81c166040519015158152f35b3461029d57608036600319011261029d576108476127a5565b61084f6127bb565b6064359167ffffffffffffffff831161029d573660238401121561029d5782600401359161087c83612964565b9261088a6040519485612942565b808452366024828701011161029d57602081600092602461029b9801838801378501015260443591612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600a6020526105856109006040600020612da5565b60405191829160208352602083019061284b565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460b01c166040519015158152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576109a29061378c565b60405160058210156109b5576020918152f35b634e487b7160e01b600052602160045260246000fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757600052600960205260206001600160801b0360026040600020015416604051908152f35b3461029d57604036600319011261029d57610a396127a5565b6024359081151580920361029d576001600160a01b0316908115610aac57336000526006602052604060002082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57600036600319011261029d5760405160006002549060018260011c9160018416918215610be3575b6020948585108414610bcd578587948686529182600014610bad575050600114610b50575b50610b3c92500383612942565b610585604051928284938452830190612780565b84915060026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace906000915b858310610b95575050610b3c935082010185610b2f565b80548389018501528794508693909201918101610b7e565b60ff191685820152610b3c95151560051b8501019250879150610b2f9050565b634e487b7160e01b600052602260045260246000fd5b92607f1692610b0a565b3461029d57600036600319011261029d5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602064ffffffffff60406000205460c81c16604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c161561031757610cb59061378c565b6005811015806109b55760028214908115610cf1575b8115610cdf575b6020826040519015158152f35b90506109b55760046020911482610cd2565b5050600381146000610ccb565b3461029d57602036600319011261029d57604051610180810181811067ffffffffffffffff821117611051576060916101609160405260008152600060208201526000604082015260008382015260006080820152600060a0820152600060c0820152600060e082015260006101008201526000610120820152610d80612d52565b6101408201520152600435600052600960205260ff60016040600020015460a81c16156110735760043560005260096020526040600020610e51600260405192610dc984612925565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612d71565b610120820152610e6260043561378c565b60058110156109b557600214611067575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e0850151151561010086015115159160043560005260036020526001600160a01b036040600020541697600a6020526040600020956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff610180828181011092011117611051576101609c610f649b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612da5565b82820152610585604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061284b565b634e487b7160e01b600052604160045260246000fd5b60006060820152610e73565b602460405162b8e7e760e51b81526004356004820152fd5b3461029d5760208060031936011261029d5760043567ffffffffffffffff811161029d576110bd90369060040161281a565b906110c6613954565b6000915b8083106110d357005b6110de838284612cf7565b35926110e8613954565b83600052600980865260ff600181816040600020015460a81c16156113cb57866000528288526040600020828282015460a01c1660001461113b5760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c6113b3576111678560005260096020526001600160a01b0360406000205416331490565b156113945761117585613714565b928560005280895261118d6002604060002001612d71565b936001600160801b039384865116858316101561137c5787600052828b5260406000205460f01c16156113645780848b816111d294818a5116031697015116906129b8565b86600052818a528960406000207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a6112b3845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a1561134b575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160406000205416998a985260406000200154169661128984878a614637565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b6112f6575b50505050600191500191906110ca565b803b1561029d5760019560006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161133c575b8080806112e6565b61134590612911565b85611334565b898601600160a01b60ff60a01b1982541617905561123b565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029d5760208060031936011261029d5760043590611400613954565b816000526009815260ff60016040600020015460a81c161561073b576114258261378c565b60058110156109b5576004810361144e5760248360405190634a5541ef60e01b82526004820152fd5b6003810361146e576024836040519063fe19f19f60e01b82526004820152fd5b6002146115e2576114958260005260096020526001600160a01b0360406000205416331490565b156115c357816000526009815260ff60406000205460f01c16156115ab578160005260098152604060002060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f600080a2600382526001600160a01b036040600020541692833b61153c575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029d57600081602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af115611510576115a590612911565b83611510565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029d57602036600319011261029d576004356001600160a01b039081811680910361029d5781600054163381036116cc575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116116b65760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b600052601160045260246000fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029d57602036600319011261029d5761170e6127a5565b6000546001600160a01b0380821692338403611760576001600160a01b03199350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029d57602036600319011261029d576001600160a01b036117a86127a5565b1680156117c75760005260046020526020604060002054604051908152f35b60246040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152fd5b3461029d57602036600319011261029d5760206118166004356136f1565b6001600160a01b0360405191168152f35b3461029d57602036600319011261029d576004356000602060405161184b816128f5565b828152015280600052600960205260ff60016040600020015460a81c16156103175760005260096020526040806000205464ffffffffff82519161188e836128f5565b818160a01c16835260c81c1660208201526118bf825180926020908164ffffffffff91828151168552015116910152565bf35b3461029d576020600319818136011261029d5760043567ffffffffffffffff9182821161029d576101208236039182011261029d576118fe613954565b60c4820135906022190181121561029d57810160048101359083821161029d57602401606082023603811361029d57611938913691612c28565b9182519161194583612c10565b926119536040519485612942565b808452601f1961196282612c10565b018660005b828110611b305750505064ffffffffff90814216936001600160801b03968761198f826139b0565b515116828a61199d846139b0565b51015116858060406119ae866139b0565b5101511689011690604051926119c3846128d9565b83528b83015260408201526119d7886139b0565b526119e1876139b0565b506001938760015b8a8c878310611aaf5790838b8b611a0281600401612d31565b92611a0f60248301612d31565b92611a1c60448401612d1d565b946064840135946001600160a01b039586811680910361029d57611aa798611a6798611a9c98611a4e60848a01612d45565b9481611a5c60a48c01612d45565b976040519d8e6128bc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612cc8565b6101008201526139d1565b604051908152f35b889385806040611ae38b86611ad38a8e9a611aca828d6139bd565b5151169a6139bd565b51015116946000198901906139bd565b51015116816040611af4888c6139bd565b5101511601169160405193611b08856128d9565b84528301526040820152611b1c828c6139bd565b52611b27818b6139bd565b500188906119e9565b611b38612d52565b828289010152018790611967565b3461029d57604036600319011261029d5767ffffffffffffffff60043581811161029d57611b7890369060040161281a565b9160243590811161029d57611b9190369060040161281a565b9091611b9b613954565b818403611c0a5760005b848110611bae57005b80611c04611bbf6001938886612cf7565b35611bcb838987612cf7565b3560005260036020526001600160a01b0360406000205416611bf6611bf185898b612cf7565b612d1d565b91611bff613954565b61335b565b01611ba5565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c16156103175761044460209161414f565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000611cb98261378c565b60058110156109b557600203611cd7575b6020906040519015158152f35b506000526009602052602060ff60406000205460f01c16611cca565b3461029d57600036600319011261029d5760206001600160a01b0360085416604051908152f35b3461029d5760208060031936011261029d5760043590611d38613954565b816000526009815260ff60016040600020015460a81c161561073b57816000526009815260ff60016040600020015460a01c1615611ec157611d79826140e6565b156115c35781600052600381526001600160a01b038060406000205416151580611eb9575b80611e9f575b611e87577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315611e4c575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611e3457005b60249060405190637e27328960e01b82526004820152fd5b611e6d85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055611de4565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615611da4565b506000611d9e565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029d57611f00366127e5565b60405191602083019383851067ffffffffffffffff8611176110515761029b9460405260008452612e35565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576000526009602052602060ff60016040600020015460a01c166040519015158152f35b3461029d5760208060031936011261029d5760043590611f9e613954565b81600052600980825260ff60016040600020015460a81c16156122235782600052808252604060002060ff600182015460a01c16600014611ff15760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61220b576120198360005260096020526001600160a01b0360406000205416331490565b156121ec5761202783613714565b8360005281835261203e6002604060002001612d71565b936001600160801b03918286511683821610156115e2578160005283855260ff60406000205460f01c16156115ab576120a6818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906129b8565b94826000528481526040600020956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881617895582169788156121d2575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5087604060002054169788938652600160406000200154169361215b8c8487614637565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b61218d57005b813b1561029d5760006084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121c957005b61029b90612911565b60018101600160a01b60ff60a01b198254161790556120ec565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029d5760031960203682011261029d5760043567ffffffffffffffff9182821161029d5761014090823603011261029d57612275613954565b60405191612282836128bc565b61228e826004016127d1565b835261229c602483016127d1565b60208401526122ad60448301612980565b604084015260648201356001600160a01b038116810361029d5760608401526122d8608483016128af565b60808401526122e960a483016128af565b60a08401526122fa60c48301612bfe565b60c084015260e482013590811161029d578101913660238401121561029d57611a9c611aa7926123366020953690602460048201359101612c28565b60e0840152610104369101612cc8565b3461029d5761029b612357366127e5565b916129d1565b3461029d57600036600319011261029d576020600754604051908152f35b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576123b59061378c565b60058110156109b55780602091159081156123d6575b506040519015158152f35b6001915014826123cb565b3461029d57602036600319011261029d5760043580600052600960205260ff60016040600020015460a81c1615610317576020906000908060005260098352604060002060ff815460f01c1680612474575b61244b575b50506001600160801b0360405191168152f35b61246d92506001600160801b0360026124679201541691613714565b906129b8565b8280612438565b5060ff600182015460a01c1615612433565b3461029d57604036600319011261029d5761249f6127a5565b6024356124ab816136f1565b33151580612574575b80612546575b6125165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a460005260056020526040600020906001600160a01b0319825416179055600080f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116600052600660205260406000203360005260205260ff60406000205416156124ba565b50336001600160a01b03821614156124b4565b3461029d57602036600319011261029d576020611816600435612994565b3461029d57600036600319011261029d576040516000600190600154918260011c9160018416918215612661575b6020948585108414610bcd578587948686529182600014610bad5750506001146126045750610b3c92500383612942565b84915060016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6906000915b858310612649575050610b3c935082010185610b2f565b80548389018501528794508693909201918101612632565b92607f16926125d3565b3461029d57600036600319011261029d57602060405167016345785d8a00008152f35b3461029d57602036600319011261029d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612733575b8115612709575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612702565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506126fb565b60005b8381106127705750506000910152565b8181015183820152602001612760565b906020916127998151809281855285808601910161275d565b601f01601f1916010190565b600435906001600160a01b038216820361029d57565b602435906001600160a01b038216820361029d57565b35906001600160a01b038216820361029d57565b606090600319011261029d576001600160a01b0390600435828116810361029d5791602435908116810361029d579060443590565b9181601f8401121561029d5782359167ffffffffffffffff831161029d576020808501948460051b01011161029d57565b90815180825260208080930193019160005b82811061286b575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161285d565b3590811515820361029d57565b610120810190811067ffffffffffffffff82111761105157604052565b6060810190811067ffffffffffffffff82111761105157604052565b6040810190811067ffffffffffffffff82111761105157604052565b67ffffffffffffffff811161105157604052565b610140810190811067ffffffffffffffff82111761105157604052565b90601f8019910116810190811067ffffffffffffffff82111761105157604052565b67ffffffffffffffff811161105157601f01601f191660200190565b35906001600160801b038216820361029d57565b61299d816136f1565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116116b657565b906001600160a01b0380911680156106f35760009184835260209160038352604092828486205416151580612bf6575b80612bde575b612bc7578685526003815282848620541694873315159384612b17575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7945087612adf575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a183168203612ab15750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612b0082600052600560205260406000206001600160a01b03198154169055565b878352600484528683208054600019019055612a4d565b91929380915090612b86575b15612b315790878392612a24565b848887612b4e576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015612bab575b80612b235750878252600583523384868420541614612b23565b5085825260068352848220338352835260ff8583205416612b91565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615612a07565b506001612a01565b359064ffffffffff8216820361029d57565b67ffffffffffffffff81116110515760051b60200190565b929192612c3482612c10565b604094612c446040519283612942565b8195848352602080930191606080960285019481861161029d57925b858410612c705750505050505050565b868483031261029d57825190612c85826128d9565b612c8e85612980565b8252858501359067ffffffffffffffff8216820361029d57828792838b950152612cb9868801612bfe565b86820152815201930192612c60565b919082604091031261029d57604051612ce0816128f5565b6020808294612cee816127d1565b84520135910152565b9190811015612d075760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361029d5790565b356001600160a01b038116810361029d5790565b35801515810361029d5790565b60405190612d5f826128d9565b60006040838281528260208201520152565b90604051612d7e816128d9565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612db181612c10565b92604093612dc26040519182612942565b82815280946020809201926000526020600020906000935b858510612de957505050505050565b60018481928451612df9816128d9565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612dda565b9190612e428282856129d1565b803b612e4f575b50505050565b612eab6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190612780565b03906020816000938185885af190829082612f41575b5050612ef85782612ed06141ca565b8051919082612ef15760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612f29575038808080612e49565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011612fa1575b81612f5e60209383612942565b81010312612f9d5751907fffffffff0000000000000000000000000000000000000000000000000000000082168203612f9a5750903880612ec1565b80fd5b5080fd5b3d9150612f51565b92919092612fb5613954565b60009381855260099260209380855260409260ff6001858a20015460a81c16156133455784885281865260ff6001858a20015460a01c1661332e576001600160a01b0391828216928315613317576001600160801b039384861691821561330057888c5260038a5280888d2054169384831415806132f0575b6132cd5761303b8a6141fa565b878116851161329c57508a8a928e928484528083528b8085209a8c848d54169c6002015460801c9061306c91614222565b878752838652828720600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556130a190612d71565b9080868301511691818481835116920151166130bc916129b8565b161115946001927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9661326f575b878252855220015416946130ff818988614637565b8a51908152a48033141580613265575b613200575b8233141590816131f5575b816131ea575b50613159575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b813b156131e6578351636fd110e960e01b8152600481018690523360248201526001600160a01b0390911660448201526001600160801b03909216606483015294957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79582908183816084810103925af16131d7575b85948161312b565b6131e090612911565b386131cf565b8780fd5b905082141538613125565b833b1515915061311f565b803b15613261578451636fd110e960e01b8152600481018790523360248201526001600160a01b03831660448201526001600160801b0385166064820152898160848183865af1613252575b50613114565b61325b90612911565b3861324c565b8880fd5b50803b151561310f565b878252808652828220848101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556130ea565b895163287ecaef60e21b8152600481018c90526001600160801b038a81166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b506132fa8a6140e6565b1561302e565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b60248585519062b8e7e760e51b82526004820152fd5b9291909260009381855260099060209382855260409260ff6001858a20015460a81c1615613345578785815281875260ff6001868320015460a01c166136da576001600160a01b03908185169283156136c3576001600160801b03938486169182156136ac5789845260038b5284898520541694858314158061369c575b613679576134008b838e6133ec8361414f565b9289525260028c8820015460801c906129b8565b87811685116136485750908b8b928387528282528b808820998b838c54169b6002015460801c9061343091614222565b868a52858552828a20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561346590612d71565b8180868301511693818351169201511661347e916129b8565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361361a575b848852825260018c8820015416946134c2818c88614637565b8b51908152a48133141580613610575b6135aa575b5081331415908161359f575b81613594575b5061351c575050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613590578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af1613578575b808061312b565b6135828691612911565b61358c5784613571565b8480fd5b8280fd5b9050811415386134e9565b823b151591506134e3565b813b15612f9a578551636fd110e960e01b8152600481018890523360248201526001600160a01b03861660448201526001600160801b0385166064820152818160848183875af16135fc575b506134d7565b61360891929a50612911565b9738806135f6565b50813b15156134d2565b8488528083528c882060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556134a9565b8a5163287ecaef60e21b8152600481018d90526001600160801b038a81166024830152919091166044820152606490fd5b60648b848c519163b34359d360e01b835260048301523360248301526044820152fd5b506136a68b6140e6565b156133d9565b60248a8a519063d2aabcd960e01b82526004820152fd5b602488885190630ff7ee2d60e31b82526004820152fd5b602486865190634a5541ef60e01b82526004820152fd5b8060005260036020526001600160a01b0360406000205416908115611e34575090565b64ffffffffff804216826000526009602052604060002091825482828260a01c1610156137825760c81c1611156137705750600a602052600160406000205411600014613767576137649061430e565b90565b6137649061423d565b6001600160801b039150600201541690565b5050505050600090565b806000526009602052604060002060ff600182015460a01c166000146137b3575050600490565b805460f81c61380c575460a01c64ffffffffff164210613806576137d681613714565b9060005260096020526001600160801b03806002604060002001541691161060001461380157600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613949575b80613931575b61391a579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138e2575b1692836138cc575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138a8565b61390386600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138a0565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561383f565b508181161515613839565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398657565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612d075760200190565b8051821015612d075760209160051b010190565b906139f36001600160801b0360408401511660206101008501510151906144ed565b6001600160801b0381511660e084015164ffffffffff60c08601511682156140bc5780156140925781518015614068577f00000000000000000000000000000000000000000000000000000000000000008111614037575064ffffffffff6040613a5c846139b0565b51015116811015613fe05750600090819082815184905b808210613f4f575050505064ffffffffff421664ffffffffff8216811015613f0f5750506001600160801b0316808203613ed8575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c0f8951996000198b01906139bd565b51015160c81b169560f01b16911617171717845560005b818110613e06575050600185016007556001600160a01b0360208301511680156106f357613c5c866001600160a01b0392613813565b16613dd557613c876001600160a01b036060840151166001600160801b0383511690309033906145c6565b6001600160801b0360208201511680613da5575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613d9a613d7b60808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613d248c6128f5565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061284b565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613dcf906001600160a01b036060850151166001600160a01b0361010086015151169033906145c6565b38613c9b565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a602052604060002090613e238160e08701516139bd565b518254680100000000000000008110156110515760018101808555811015612d0757600193600052602060002001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613c26565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613f73906001600160801b03613f6a85886139bd565b51511690614222565b9364ffffffffff806040613f8786856139bd565b51015116941680851115613fa357506001849301909291613a73565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613ff1846139b0565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b03806040842054169283331493841561412b575b5050821561411957505090565b9091506141263392612994565b161490565b60ff929450906040918152600660205281812033825260205220541691388061410c565b8060005260096020526141686002604060002001612d71565b816000526009602052604060002060ff600182015460a01c1660001461419b57506001600160801b039150602001511690565b5460f81c6141ad575061376490613714565b61376491506001600160801b0360408183511692015116906129b8565b3d156141f5573d906141db82612964565b916141e96040519384612942565b82523d6000602084013e565b606090565b613764906142078161414f565b90600052600960205260026040600020015460801c906129b8565b9190916001600160801b03808094169116019182116116b657565b64ffffffffff614272600091838352600960205280806040852054818160a01c1693849160c81c160316918142160316614691565b91808252600a602052604082208054156142fa5790829167ffffffffffffffff93526142cc602083205482845260096020526142c76001600160801b03968760026040882001541696879360801c1690614781565b6147ef565b9283136142e25750506142de906148d9565b1690565b60029350604092508152600960205220015460801c90565b602483634e487b7160e01b81526032600452fd5b64ffffffffff804216600083815260096020526040918282209083519161433483612925565b8054966101206143ba60026001600160a01b0394858c168852602088019b8b8160a01c168d528b8160c81c168b8a015260ff8160f01c16151560608a015260f81c1515608089015260ff600196600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612d71565b94019384528452600a6020526143d1858520612da5565b91849680876143df866139b0565b5101511692828288955b16106144b757509161445d6142c79284888161446298976001600160801b039e8f614414898c6139bd565b5151169d8e9a67ffffffffffffffff602061442f8c846139bd565b5101511699848361444083856139bd565b5101511696508061449c57505050511680925b0316920316614691565b614781565b92831361447b57505061447583916148d9565b16011690565b5160200151929392831692841683101591506144979050575090565b905090565b6144ac92935060001901906139bd565b510151168092614453565b8093986001600160801b0390816144ce8c896139bd565b51511601169801928282808a6144e4888a6139bd565b510151166143e9565b919091604051906144fd826128f5565b600091828152826020820152936001600160801b03928383169182156145a75767016345785d8a000080821161457057506145398591846154a1565b166020870192818452111561455c57509082614557925116906129b8565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50939450505050604051906145bb826128f5565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff8411176110515761463592604052614915565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526146359161468c606483612942565b614915565b600160ff1b808214908115614777575b5061474d576000811215614744576146ca816000035b600084121561473d5783600003906149b1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470657600019911813156147005790565b60000390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906149b1565b6146ca816146b7565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b90508214386146a1565b8061479c575061479757670de0b6b3a764000090565b600090565b90670de0b6b3a76400008083146147e95750806147c1575050670de0b6b3a764000090565b670de0b6b3a764000081146147e5576147e0906142c761376493614aab565b614bed565b5090565b91505090565b600160ff1b8082149081156148cf575b506148a557600081121561489c57614828816000035b60008412156148955783600003906154a1565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485e57600019911813156147005790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b83906154a1565b61482881614815565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b90508214386147ff565b600081126148e45790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b6001600160a01b031690614940600080836020829551910182875af16149396141ca565b9084615550565b908151918215159283614989575b5050506149585750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312612f9d576020015190811591821503612f9a575038808061494e565b670de0b6b3a7640000916000198383099280830292838086109503948086039514614a6d5782851015614a3157908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b505080925015614a7b570490565b634e487b7160e01b600052601260045260246000fd5b8015614a7b576ec097ce7bc90715b34b9f10000000000590565b80600080831315614bbc57670de0b6b3a764000092838112614b9957506001925b808305906001600160801b03821160071b91821c9167ffffffffffffffff831160061b92831c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600197600160038711811b96871c11961717171717171781810294811d90828214614b8d57506706f05b59d3b20000905b848213614b615750505050500290565b808391020590671bc16d674ec80000821215614b80575b831d90614b51565b8091950194831d90614b78565b93505093925050020290565b6000199392508015614a7b576ec097ce7bc90715b34b9f10000000000591614acc565b602483604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b6000811215614c1c5768033dd1780914b9711419811261380657614c1390600003614bed565b61376490614a91565b680a688906bd8affffff811361547057670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff000000000000008316615353575b66ff000000000000831661524b575b65ff0000000000831661514b575b64ff000000008316615053575b63ff0000008316614f63575b62ff00008316614e7b575b61ff008316614d9b575b60ff8316614cc4575b02911c60bf031c90565b60808316614d89575b838316614d77575b60208316614d65575b60108316614d53575b60088316614d41575b60048316614d2f575b60028316614d1d575b6001831615614cba576801000000000000000102831c614cba565b6801000000000000000102831c614d02565b6801000000000000000302831c614cf9565b6801000000000000000602831c614cf0565b6801000000000000000b02831c614ce7565b6801000000000000001602831c614cde565b6801000000000000002c02831c614cd5565b6801000000000000005902831c614ccd565b6180008316614e69575b6140008316614e57575b6120008316614e45575b6110008316614e33575b6108008316614e21575b6104008316614e0f575b6102008316614dfd575b610100831615614cb157680100000000000000b102831c614cb1565b6801000000000000016302831c614de1565b680100000000000002c602831c614dd7565b6801000000000000058c02831c614dcd565b68010000000000000b1702831c614dc3565b6801000000000000162e02831c614db9565b68010000000000002c5d02831c614daf565b680100000000000058b902831c614da5565b628000008316614f51575b624000008316614f3f575b622000008316614f2d575b621000008316614f1b575b620800008316614f09575b620400008316614ef7575b620200008316614ee5575b62010000831615614ca7576801000000000000b17202831c614ca7565b680100000000000162e402831c614ec8565b6801000000000002c5c802831c614ebd565b68010000000000058b9102831c614eb2565b680100000000000b172102831c614ea7565b68010000000000162e4302831c614e9c565b680100000000002c5c8602831c614e91565b6801000000000058b90c02831c614e86565b63800000008316615041575b6340000000831661502f575b6320000000831661501d575b6310000000831661500b575b63080000008316614ff9575b63040000008316614fe7575b63020000008316614fd5575b6301000000831615614c9c5768010000000000b1721802831c614c9c565b6801000000000162e43002831c614fb7565b68010000000002c5c86002831c614fab565b680100000000058b90c002831c614f9f565b6801000000000b17217f02831c614f93565b680100000000162e42ff02831c614f87565b6801000000002c5c85fe02831c614f7b565b68010000000058b90bfc02831c614f6f565b6480000000008316615139575b6440000000008316615127575b6420000000008316615115575b6410000000008316615103575b64080000000083166150f1575b64040000000083166150df575b64020000000083166150cd575b640100000000831615614c9057680100000000b17217f802831c614c90565b68010000000162e42ff102831c6150ae565b680100000002c5c85fe302831c6150a1565b6801000000058b90bfce02831c615094565b68010000000b17217fbb02831c615087565b6801000000162e42fff002831c61507a565b68010000002c5c8601cc02831c61506d565b680100000058b90c0b4902831c615060565b658000000000008316615239575b654000000000008316615227575b652000000000008316615215575b651000000000008316615203575b6508000000000083166151f1575b6504000000000083166151df575b6502000000000083166151cd575b65010000000000831615614c83576801000000b17218355102831c614c83565b680100000162e430e5a202831c6151ad565b6801000002c5c863b73f02831c61519f565b68010000058b90cf1e6e02831c615191565b680100000b1721bcfc9a02831c615183565b68010000162e43f4f83102831c615175565b680100002c5c89d5ec6d02831c615167565b6801000058b91b5bc9ae02831c615159565b66800000000000008316615341575b6640000000000000831661532f575b6620000000000000831661531d575b6610000000000000831661530b575b660800000000000083166152f9575b660400000000000083166152e7575b660200000000000083166152d5575b6601000000000000831615614c755768010000b17255775c0402831c614c75565b6801000162e525ee054702831c6152b4565b68010002c5cc37da949202831c6152a5565b680100058ba01fb9f96d02831c615296565b6801000b175effdc76ba02831c615287565b680100162f3904051fa102831c615278565b6801002c605e2e8cec5002831c615269565b68010058c86da1c09ea202831c61525a565b6780000000000000008316615451575b674000000000000000831661543f575b672000000000000000831661542d575b671000000000000000831661541b575b6708000000000000008316615409575b67040000000000000083166153f7575b67020000000000000083166153e5575b670100000000000000831615614c6657680100b1afa5abcbed6102831c614c66565b68010163da9fb33356d802831c6153c3565b680102c9a3e778060ee702831c6153b3565b6801059b0d31585743ae02831c6153a3565b68010b5586cf9890f62a02831c615393565b6801172b83c7d517adce02831c615383565b6801306fe0a31b7152df02831c615373565b5077b504f333f9de648480000000000000000000000000000000615363565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091906000198382098382029182808310920391808303921461553f57670de0b6b3a7640000908183101561550857947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061558f575080511561556557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806155da575b6155a0575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561559856fea164736f6c6343000817000a"; + hex"60c034620003c3576001600160401b0390601f601f196200584d3881900383810183168501919086831186841017620002e557808692606094604052833981010312620003c35782516001600160a01b038082169590929091869003620003c35760209485810151938416809403620003c357604001519362000081620003c7565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003c7565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002e5576001988954908a82811c92168015620003b8575b84831014620002c657818684931162000365575b50839086831160011462000305575f92620002f9575b50505f19600383901b1c191690891b1788555b8151948511620002e557600254938885811c95168015620002da575b82861014620002c65784848796116200026c575b5081938511600114620002065750505f92620001fa575b50505f19600383901b1c191690841b176002555b60018060a01b031984815f5416175f556008541617600855604051925f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556154659081620003e8823960805181613830015260a051818181610bb901526138f70152f35b015190505f8062000179565b8895939291931660025f52835f20935f905b82821062000252575050841162000239575b505050811b016002556200018d565b01515f1960f88460031b161c191690555f80806200022a565b8484015186558a9790950194938401939081019062000218565b90919293945060025f52825f208580880160051c820192858910620002bc575b9188978c9297969594930160051c01915b828110620002ad57505062000162565b5f81558897508b91016200029d565b925081926200028c565b634e487b7160e01b5f52602260045260245ffd5b94607f16946200014e565b634e487b7160e01b5f52604160045260245ffd5b015190505f806200011f565b90878c941691845f52855f20925f5b878282106200034e575050841162000335575b505050811b01885562000132565b01515f1960f88460031b161c191690555f808062000327565b8385015186558f9790950194938401930162000314565b9091508a5f52835f208680850160051c820192868610620003ae575b918d91869594930160051c01915b8281106200039f57505062000109565b5f81558594508d91016200038f565b9250819262000381565b91607f1691620000f5565b5f80fd5b60408051919082016001600160401b03811183821017620002e55760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146125b257508063027b67441461259057806306fdde03146124cf578063081812fc146124b1578063095ea7b3146123b85780631400ecec146123185780631c1cdd4c146122b45780631e99d5691461229757806323b872dd1461228057806331df3d481461217457806340e58ee514611eca578063425d30dd14611e7a57806342842e0e14611e4157806342966c6814611c7b5780634426757014611c555780634857501f14611be45780634869e12d14611baa5780634cc55e1114611ab257806354c022921461182f57806357404b121461179a5780636352211e1461176b5780636d0cee751461176b57806370a08231146116fd57806375829def1461166e5780637cad6cd1146115775780637de6b1db1461136a5780638659c27014611024578063894e9a0d14610cab5780638f69b99314610c2b5780639067b67714610bdc5780639188ec8414610ba257806395d89b4114610a99578063a22cb465146109e0578063a80fc0711461098f578063ad35efd414610930578063b2564569146108e0578063b637b86514610887578063b88d4fde146107ff578063b8a3be66146107ca578063b971302a1461077c578063bc2be1be1461072d578063c156a11d146105ee578063c87b56dd146104dd578063d4dbd20b1461048c578063d511609f14610441578063d975dfed146103f6578063e985e9c5146103a3578063ea5ead1914610375578063eac8f5b814610324578063f590c176146102c3578063f851a4401461029e5763fdd46d6014610258575f80fd5b3461029a57606036600319011261029a576102716126dd565b6044356001600160801b038116810361029a5761029891610290613826565b600435613247565b005b5f80fd5b3461029a575f36600319011261029a5760206001600160a01b035f5416604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060405f205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160a01b03600160405f20015416604051908152f35b3461029a57604036600319011261029a576102986004356103946126dd565b61039d826140b8565b91612ea8565b3461029a57604036600319011261029a576103bc6126c7565b6103c46126dd565b906001600160a01b038091165f52600660205260405f2091165f52602052602060ff60405f2054166040519015158152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576104306020916140b8565b6001600160801b0360405191168152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f5260096020526020600260405f20015460801c604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160801b03600360405f20015416604051908152f35b3461029a5760208060031936011261029a57600435906104fc826135d7565b505f6001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156105e3575f9261056b575b506105676040519282849384528301906126a2565b0390f35b9091503d805f833e61057d8183612863565b810190828183031261029a5780519067ffffffffffffffff821161029a570181601f8201121561029a5780516105b281612885565b926105c06040519485612863565b81845284828401011161029a576105dc91848085019101612681565b9082610552565b6040513d5f823e3d90fd5b3461029a57604036600319011261029a5760043561060a6126dd565b610612613826565b815f52600960205260ff600160405f20015460a81c161561071657815f5260036020526001600160a01b038060405f205416918233036106f757610655846140b8565b6001600160801b0381166106e6575b50818116156106cf5783610677916136eb565b908116806106975760248460405190637e27328960e01b82526004820152fd5b820361069f57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b81525f6004820152fd5b6106f1908486612ea8565b84610664565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602064ffffffffff60405f205460a01c16604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160a01b0360405f205416604051908152f35b3461029a57602036600319011261029a576004355f526009602052602060ff600160405f20015460a81c166040519015158152f35b3461029a57608036600319011261029a576108186126c7565b6108206126dd565b6064359167ffffffffffffffff831161029a573660238401121561029a5782600401359161084d83612885565b9261085b6040519485612863565b808452366024828701011161029a576020815f9260246102989801838801378501015260443591612d41565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600a6020526105676108cc60405f20612cb4565b60405191829160208352602083019061276d565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060ff600160405f20015460b01c166040519015158152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576109689061366b565b604051600582101561097b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160801b03600260405f20015416604051908152f35b3461029a57604036600319011261029a576109f96126c7565b6024359081151580920361029a576001600160a01b0316908115610a6857335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029a575f36600319011261029a576040515f6002549060018260011c9160018416918215610b98575b6020948585108414610b845785879486865291825f14610b64575050600114610b09575b50610af592500383612863565b6105676040519282849384528301906126a2565b84915060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace905f915b858310610b4c575050610af5935082010185610ae8565b80548389018501528794508693909201918101610b35565b60ff191685820152610af595151560051b8501019250879150610ae89050565b634e487b7160e01b5f52602260045260245ffd5b92607f1692610ac4565b3461029a575f36600319011261029a5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602064ffffffffff60405f205460c81c16604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d57610c639061366b565b60058110158061097b5760028214908115610c9f575b8115610c8d575b6020826040519015158152f35b905061097b5760046020911482610c80565b5050600381145f610c79565b3461029a57602036600319011261029a57604051610180810181811067ffffffffffffffff821117610fed57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d23612c62565b61014082015201526004355f52600960205260ff600160405f20015460a81c161561100c576004355f52600960205260405f20610df0600260405192610d6884612846565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612c80565b610120820152610e0160043561366b565b600581101561097b57600214611001575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e085015115156101008601511515916004355f5260036020526001600160a01b0360405f20541697600a60205260405f20956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff610180828181011092011117610fed576101609c610f009b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612cb4565b82820152610567604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061276d565b634e487b7160e01b5f52604160045260245ffd5b5f6060820152610e12565b602460405162b8e7e760e51b81526004356004820152fd5b3461029a5760208060031936011261029a5760043567ffffffffffffffff811161029a5761105690369060040161273c565b9061105f613826565b5f915b80831061106b57005b611076838284612c09565b3592611080613826565b835f52600980865260ff6001818160405f20015460a81c161561135357865f5282885260405f20828282015460a01c165f146110ce5760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c61133b576110f8855f5260096020526001600160a01b0360405f205416331490565b1561131c57611106856135f8565b92855f5280895261111c600260405f2001612c80565b936001600160801b039384865116858316101561130457875f52828b5260405f205460f01c16156112ec5780848b8161115f94818a5116031697015116906128d7565b865f52818a528960405f207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a61123c845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a156112d3575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160405f205416998a985260405f200154169661121284878a6144cd565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61127f575b5050505060019150019190611062565b803b1561029a576001955f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16112c4575b80808061126f565b6112cd90612832565b856112bc565b898601600160a01b60ff60a01b198254161790556111c6565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029a5760208060031936011261029a5760043590611388613826565b815f526009815260ff600160405f20015460a81c1615610716576113ab8261366b565b600581101561097b57600481036113d45760248360405190634a5541ef60e01b82526004820152fd5b600381036113f4576024836040519063fe19f19f60e01b82526004820152fd5b60021461155f57611419825f5260096020526001600160a01b0360405f205416331490565b1561154057815f526009815260ff60405f205460f01c161561152857815f526009815260405f2060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a2600382526001600160a01b0360405f20541692833b6114ba575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029a575f81602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af11561148e5761152290612832565b8361148e565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029a57602036600319011261029a576004356001600160a01b039081811680910361029a57815f5416338103611645575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116315760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029a57602036600319011261029a576116876126c7565b5f546001600160a01b03808216923384036116d6576001600160a01b031993501691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029a57602036600319011261029a576001600160a01b0361171e6126c7565b16801561173b575f526004602052602060405f2054604051908152f35b60246040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152fd5b3461029a57602036600319011261029a5760206117896004356135d7565b6001600160a01b0360405191168152f35b3461029a57602036600319011261029a576004355f60206040516117bd81612816565b8281520152805f52600960205260ff600160405f20015460a81c161561030d575f5260096020526040805f205464ffffffffff8251916117fc83612816565b818160a01c16835260c81c16602082015261182d825180926020908164ffffffffff91828151168552015116910152565bf35b3461029a576020600319818136011261029a5760043567ffffffffffffffff9182821161029a576101208236039182011261029a5761186c613826565b60c4820135906022190181121561029a57810160048101359083821161029a57602401606082023603811361029a576118a6913691612b3a565b918251916118b383612b22565b926118c16040519485612863565b808452601f196118d082612b22565b01865f5b828110611a9c5750505064ffffffffff90814216936001600160801b0396876118fc82613882565b515116828a61190a84613882565b510151168580604061191b86613882565b510151168901169060405192611930846127fa565b83528b830152604082015261194488613882565b5261194e87613882565b506001938760015b8a8c878310611a1c5790838b8b61196f81600401612c41565b9261197c60248301612c41565b9261198960448401612c2d565b946064840135946001600160a01b039586811680910361029a57611a14986119d498611a09986119bb60848a01612c55565b94816119c960a48c01612c55565b976040519d8e6127dd565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612bda565b6101008201526138a3565b604051908152f35b889385806040611a4f8b86611a408a8e9a611a37828d61388f565b5151169a61388f565b51015116945f1989019061388f565b51015116816040611a60888c61388f565b5101511601169160405193611a74856127fa565b84528301526040820152611a88828c61388f565b52611a93818b61388f565b50018890611956565b611aa4612c62565b8282890101520187906118d4565b3461029a57604036600319011261029a5767ffffffffffffffff60043581811161029a57611ae490369060040161273c565b9160243590811161029a57611afd90369060040161273c565b9091611b07613826565b818403611b73575f5b848110611b1957005b80611b6d611b2a6001938886612c09565b35611b36838987612c09565b355f5260036020526001600160a01b0360405f205416611b5f611b5a85898b612c09565b612c2d565b91611b68613826565b613247565b01611b10565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d57610430602091614013565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f611c1d8261366b565b600581101561097b57600203611c3b575b6020906040519015158152f35b505f526009602052602060ff60405f205460f01c16611c2e565b3461029a575f36600319011261029a5760206001600160a01b0360085416604051908152f35b3461029a5760208060031936011261029a5760043590611c99613826565b815f526009815260ff600160405f20015460a81c161561071657815f526009815260ff600160405f20015460a01c1615611e1057611cd682613fae565b1561154057815f52600381526001600160a01b038060405f205416151580611e09575b80611df0575b611dd8577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f205416918215928315611da2575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611d8a57005b60249060405190637e27328960e01b82526004820152fd5b611dc1855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f198154019055611d3d565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c1615611cff565b505f611cf9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029a57611e4f36612707565b60405191602083019383851067ffffffffffffffff861117610fed57610298946040525f8452612d41565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060ff600160405f20015460a01c166040519015158152f35b3461029a5760208060031936011261029a5760043590611ee8613826565b815f52600980825260ff600160405f20015460a81c161561215d57825f5280825260405f2060ff600182015460a01c165f14611f365760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61214557611f5c835f5260096020526001600160a01b0360405f205416331490565b1561212657611f6a836135f8565b835f52818352611f7f600260405f2001612c80565b936001600160801b039182865116838216101561155f57815f5283855260ff60405f205460f01c161561152857611fe5818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906128d7565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8816178955821697881561210c575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f20015416936120968c84876144cd565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b6120c857005b813b1561029a575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161210357005b61029890612832565b60018101600160a01b60ff60a01b19825416179055612029565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029a5760031960203682011261029a5760043567ffffffffffffffff9182821161029a5761014090823603011261029a576121af613826565b604051916121bc836127dd565b6121c8826004016126f3565b83526121d6602483016126f3565b60208401526121e7604483016128a1565b604084015260648201356001600160a01b038116810361029a576060840152612212608483016127d0565b608084015261222360a483016127d0565b60a084015261223460c48301612b10565b60c084015260e482013590811161029a578101913660238401121561029a57611a09611a14926122706020953690602460048201359101612b3a565b60e0840152610104369101612bda565b3461029a5761029861229136612707565b916128f0565b3461029a575f36600319011261029a576020600754604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576122ec9061366b565b600581101561097b57806020911590811561230d575b506040519015158152f35b600191501482612302565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576020905f90805f526009835260405f2060ff815460f01c16806123a6575b61237d575b50506001600160801b0360405191168152f35b61239f92506001600160801b03600261239992015416916135f8565b906128d7565b828061236a565b5060ff600182015460a01c1615612365565b3461029a57604036600319011261029a576123d16126c7565b6024356123dd816135d7565b3315158061249e575b80612474575b6124445781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f205416156123ec565b50336001600160a01b03821614156123e6565b3461029a57602036600319011261029a5760206117896004356128b5565b3461029a575f36600319011261029a576040515f600190600154918260011c9160018416918215612586575b6020948585108414610b845785879486865291825f14610b6457505060011461252b5750610af592500383612863565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b85831061256e575050610af5935082010185610ae8565b80548389018501528794508693909201918101612557565b92607f16926124fb565b3461029a575f36600319011261029a57602060405167016345785d8a00008152f35b3461029a57602036600319011261029a57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029a57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612657575b811561262d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612626565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061261f565b5f5b8381106126925750505f910152565b8181015183820152602001612683565b906020916126bb81518092818552858086019101612681565b601f01601f1916010190565b600435906001600160a01b038216820361029a57565b602435906001600160a01b038216820361029a57565b35906001600160a01b038216820361029a57565b606090600319011261029a576001600160a01b0390600435828116810361029a5791602435908116810361029a579060443590565b9181601f8401121561029a5782359167ffffffffffffffff831161029a576020808501948460051b01011161029a57565b9081518082526020808093019301915f5b82811061278c575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161277e565b3590811515820361029a57565b610120810190811067ffffffffffffffff821117610fed57604052565b6060810190811067ffffffffffffffff821117610fed57604052565b6040810190811067ffffffffffffffff821117610fed57604052565b67ffffffffffffffff8111610fed57604052565b610140810190811067ffffffffffffffff821117610fed57604052565b90601f8019910116810190811067ffffffffffffffff821117610fed57604052565b67ffffffffffffffff8111610fed57601f01601f191660200190565b35906001600160801b038216820361029a57565b6128be816135d7565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b03918216908216039190821161163157565b906001600160a01b038091169081156106cf57835f526020906003825260409181835f205416151580612b08575b80612af0575b612ad957855f526003815281835f2054169333151580612a32575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856129fd575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036129cf5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612a1c885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f198154019055612969565b80612a98575b15612a43575f61293f565b838786612a60576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503385148015612abd575b80612a385750865f52600582523383855f20541614612a38565b50845f5260068252835f20335f52825260ff845f205416612aa3565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c1615612924565b50600161291e565b359064ffffffffff8216820361029a57565b67ffffffffffffffff8111610fed5760051b60200190565b929192612b4682612b22565b604094612b566040519283612863565b8195848352602080930191606080960285019481861161029a57925b858410612b825750505050505050565b868483031261029a57825190612b97826127fa565b612ba0856128a1565b8252858501359067ffffffffffffffff8216820361029a57828792838b950152612bcb868801612b10565b86820152815201930192612b72565b919082604091031261029a57604051612bf281612816565b6020808294612c00816126f3565b84520135910152565b9190811015612c195760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361029a5790565b356001600160a01b038116810361029a5790565b35801515810361029a5790565b60405190612c6f826127fa565b5f6040838281528260208201520152565b90604051612c8d816127fa565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612cc081612b22565b92604093612cd16040519182612863565b82815280946020809201925f5260205f20905f935b858510612cf557505050505050565b60018481928451612d05816127fa565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612ce6565b91929092612d508185856128f0565b833b612d5d575b50505050565b6020906001600160a01b0380951694612dbe60405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906126a2565b03815f875af15f9181612e4b575b50612e025782612dda614089565b8051919082612dfb5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612e3357505f808080612d57565b60249060405190633250574960e11b82526004820152fd5b9091506020813d602011612ea0575b81612e6760209383612863565b8101031261029a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361029a57905f612dcc565b3d9150612e5a565b612eb0613826565b805f5260099160209280845260409160ff6001845f20015460a81c161561323157835f5281855260ff6001845f20015460a01c1661321a576001600160a01b03808216928315613203576001600160801b03938489169182156131ec57875f526003895283875f2054169384831415806131dc575b6131b957612f32896140b8565b8781168511613188575090898992835f52828252895f20988d828b54169a6002015460801c90612f61916140de565b855f528484528b5f20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155612f9690612c80565b9080848301511691818d8183511692015116612fb1916128d7565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361315a575b845f52825260018a5f2001541694612ff58189886144cd565b8951908152a48033141580613150575b6130ef575b8233141590816130e4575b816130d9575b5061304d575b50507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7935051908152a1565b813b1561029a578251636fd110e960e01b8152600481018590523360248201526001600160a01b0390911660448201526001600160801b0390951660648601527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794905f9082908183816084810103925af16130ca575b80613021565b6130d390612832565b5f6130c4565b90508214155f61301b565b833b15159150613015565b803b1561029a578351636fd110e960e01b8152600481018690523360248201526001600160a01b03831660448201526001600160801b03881660648201525f8160848183865af1613141575b5061300a565b61314a90612832565b5f61313b565b50803b1515613005565b845f528083528a5f2060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612fdc565b885163287ecaef60e21b8152600481018b90526001600160801b038d81166024830152919091166044820152606490fd5b606489848a519163b34359d360e01b835260048301523360248301526044820152fd5b506131e689613fae565b15612f25565b60248888519063d2aabcd960e01b82526004820152fd5b602486865190630ff7ee2d60e31b82526004820152fd5b602484845190634a5541ef60e01b82526004820152fd5b60248484519062b8e7e760e51b82526004820152fd5b929192805f5260099360209285845260409160ff6001845f20015460a81c1615613231575f96845f5280865260ff6001855f20015460a01c166135c0576001600160a01b038084169182156135a9576001600160801b039283851691821561359257885f5260038a5283885f205416938483141580613582575b61355f576132e76132d18b614013565b8b5f52838d5260028b5f20015460801c906128d7565b868116851161352e5750908a8a92835f528282528a805f20988a838b54169a6002015460801c90613317916140de565b865f52858552825f20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561334c90612c80565b81808683015116938183511692015116613365916128d7565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613500575b845f52825260018b5f20015416946133a9818b886144cd565b8a51908152a480331415806134f6575b613491575b813314159081613486575b8161347b575b50613403575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613477578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af161345f575b80806133d5565b6134698691612832565b6134735784613458565b8480fd5b8280fd5b90508114155f6133cf565b823b151591506133c9565b803b1561029a578451636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b03841660648201525f8160848183865af16134e3575b506133be565b6134ee919950612832565b5f975f6134dd565b50803b15156133b9565b845f528083528b5f2060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613390565b895163287ecaef60e21b8152600481018c90526001600160801b038981166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061358c8a613fae565b156132c1565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b805f5260036020526001600160a01b0360405f205416908115611d8a575090565b64ffffffffff804216825f52600960205260405f2091825482828260a01c1610156136625760c81c1611156136505750600a602052600160405f2054115f1461364757613644906141b1565b90565b613644906140f9565b6001600160801b039150600201541690565b50505050505f90565b805f52600960205260405f2060ff600182015460a01c165f1461368f575050600490565b805460f81c6136e4575460a01c64ffffffffff1642106136df576136b2816135f8565b905f5260096020526001600160801b0380600260405f200154169116105f146136da57600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f20541615158061381b575b80613803575b6137ec578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f20541692836137b7575b1692836137a1575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f206001815401905561375a565b6137d6835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613752565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613715565b50858116151561370f565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361385857565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c195760200190565b8051821015612c195760209160051b010190565b906138c56001600160801b03604084015116602061010085015101519061438a565b6001600160801b0381511660e084015164ffffffffff60c0860151168215613f84578015613f5a5781518015613f30577f00000000000000000000000000000000000000000000000000000000000000008111613eff575064ffffffffff604061392e84613882565b51015116811015613ea857505f905f905f81515f905b808210613e17575050505064ffffffffff421664ffffffffff8216811015613dd75750506001600160801b0316808203613da057505060075492835f52600960205260405f20916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613add8951995f198b019061388f565b51015160c81b169560f01b1691161717171784555f5b818110613cd2575050600185016007556001600160a01b0360208301511680156106cf57613b29866001600160a01b03926136eb565b16613ca257613b546001600160a01b036060840151166001600160801b03835116903090339061445c565b6001600160801b0360208201511680613c72575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613c67613c4860808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613bf18c612816565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061276d565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613c9c906001600160a01b036060850151166001600160a01b03610100860151511690339061445c565b5f613b68565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b865f52600a60205260405f2090613ced8160e087015161388f565b51825468010000000000000000811015610fed5760018101808555811015612c19576001935f5260205f2001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613af3565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613e3b906001600160801b03613e32858861388f565b515116906140de565b9364ffffffffff806040613e4f868561388f565b51015116941680851115613e6b57506001849301909291613944565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613eb984613882565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f20541691823314928315613ff0575b508215613fde57505090565b909150613feb33926128b5565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f613fd2565b805f52600960205261402a600260405f2001612c80565b815f52600960205260405f2060ff600182015460a01c165f1461405a57506001600160801b039150602001511690565b5460f81c61406c5750613644906135f8565b61364491506001600160801b0360408183511692015116906128d7565b3d156140b3573d9061409a82612885565b916140a86040519384612863565b82523d5f602084013e565b606090565b613644906140c581614013565b905f526009602052600260405f20015460801c906128d7565b9190916001600160801b038080941691160191821161163157565b61412b64ffffffffff825f526009602052808060405f2054818160a01c1693849160c81c160316918142160316614527565b90805f52600a60205260405f2090815415612c195767ffffffffffffffff915f5261418460205f2054825f52600960205261417f6001600160801b039586600260405f2001541695869360801c1690614611565b61467e565b918213614199575061419590614763565b1690565b9150505f526009602052600260405f20015460801c90565b64ffffffffff80421691805f526009602052604092835f20938051916141d683612846565b85549361012061425c60026001600160a01b03998a8916885260208801988a8160a01c168a528a8160c81c16888a015260ff8160f01c16151560608a015260f81c1515608089015260ff60019b600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612c80565b94019384525f52600a602052614273825f20612cb4565b905f95808461428185613882565b510151169782825f9a5b16106143545750916142fd61417f9261430295946001600160801b039a81808d6142b5848961388f565b5151169b8c9967ffffffffffffffff60206142d0878c61388f565b510151169883826142e1888461388f565b51015116958061433a57505050511680925b0316920316614527565b614611565b91821361431a57506143148391614763565b16011690565b83929391506020905101511680918316115f14614335575090565b905090565b6143499293505f19019061388f565b5101511680926142f3565b8098976001600160801b03908161436b8b8861388f565b5151160116970197828280876143818d8961388f565b5101511661428b565b91909160405161439981612816565b5f81525f6020820152926001600160801b039182811691821561443e5767016345785d8a000080821161440757506143d2849184615317565b16602086019281845211156143f357826143ee925116906128d7565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050905060405161445081612816565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117610fed576144cb9260405261479e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526144cb91614522606483612863565b61479e565b600160ff1b808214908115614607575b506145dd575f8112156145d45761455c815f035b5f8412156145cd57835f0390614832565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614596575f19911813156145915790565b5f0390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614832565b61455c8161454b565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b905082145f614537565b8061462b575061462757670de0b6b3a764000090565b5f90565b90670de0b6b3a7640000808314614678575080614650575050670de0b6b3a764000090565b670de0b6b3a764000081146146745761466f9061417f61364493614928565b614a65565b5090565b91505090565b600160ff1b808214908115614759575b5061472f575f811215614726576146b3815f035b5f84121561471f57835f0390615317565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116146e8575f19911813156145915790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615317565b6146b3816146a2565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b905082145f61468e565b5f811261476d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b5f806001600160a01b036147c793169360208151910182865af16147c0614089565b90836153c5565b805190811515918261480e575b50506147dd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261029a576020015180159081150361029a575f806147d4565b670de0b6b3a7640000915f1983830992808302928380861095039480860395146148ec57828510156148b0579082910960018219018216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156148fa570490565b634e487b7160e01b5f52601260045260245ffd5b80156148fa576ec097ce7bc90715b34b9f10000000000590565b805f821315614a3457670de0b6b3a764000091828112614a1257506001915b8082056001600160801b03811160071b90811c9067ffffffffffffffff821160061b91821c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600196600160038711811b96871c1196171717171717179180830293831d92818414614a0757506706f05b59d3b20000925b5f84136149db57505050500290565b808291020592671bc16d674ec800008412156149fa575b821d926149cc565b8093940193821d926149f2565b925093925050020290565b5f1992915080156148fa576ec097ce7bc90715b34b9f10000000000590614947565b602482604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b5f811215614a925768033dd1780914b971141981126136df57614a89905f03614a65565b6136449061490e565b680a688906bd8affffff81136152e657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166151c9575b66ff00000000000083166150c1575b65ff00000000008316614fc1575b64ff000000008316614ec9575b63ff0000008316614dd9575b62ff00008316614cf1575b61ff008316614c11575b60ff8316614b3a575b02911c60bf031c90565b60808316614bff575b838316614bed575b60208316614bdb575b60108316614bc9575b60088316614bb7575b60048316614ba5575b60028316614b93575b6001831615614b30576801000000000000000102831c614b30565b6801000000000000000102831c614b78565b6801000000000000000302831c614b6f565b6801000000000000000602831c614b66565b6801000000000000000b02831c614b5d565b6801000000000000001602831c614b54565b6801000000000000002c02831c614b4b565b6801000000000000005902831c614b43565b6180008316614cdf575b6140008316614ccd575b6120008316614cbb575b6110008316614ca9575b6108008316614c97575b6104008316614c85575b6102008316614c73575b610100831615614b2757680100000000000000b102831c614b27565b6801000000000000016302831c614c57565b680100000000000002c602831c614c4d565b6801000000000000058c02831c614c43565b68010000000000000b1702831c614c39565b6801000000000000162e02831c614c2f565b68010000000000002c5d02831c614c25565b680100000000000058b902831c614c1b565b628000008316614dc7575b624000008316614db5575b622000008316614da3575b621000008316614d91575b620800008316614d7f575b620400008316614d6d575b620200008316614d5b575b62010000831615614b1d576801000000000000b17202831c614b1d565b680100000000000162e402831c614d3e565b6801000000000002c5c802831c614d33565b68010000000000058b9102831c614d28565b680100000000000b172102831c614d1d565b68010000000000162e4302831c614d12565b680100000000002c5c8602831c614d07565b6801000000000058b90c02831c614cfc565b63800000008316614eb7575b63400000008316614ea5575b63200000008316614e93575b63100000008316614e81575b63080000008316614e6f575b63040000008316614e5d575b63020000008316614e4b575b6301000000831615614b125768010000000000b1721802831c614b12565b6801000000000162e43002831c614e2d565b68010000000002c5c86002831c614e21565b680100000000058b90c002831c614e15565b6801000000000b17217f02831c614e09565b680100000000162e42ff02831c614dfd565b6801000000002c5c85fe02831c614df1565b68010000000058b90bfc02831c614de5565b6480000000008316614faf575b6440000000008316614f9d575b6420000000008316614f8b575b6410000000008316614f79575b6408000000008316614f67575b6404000000008316614f55575b6402000000008316614f43575b640100000000831615614b0657680100000000b17217f802831c614b06565b68010000000162e42ff102831c614f24565b680100000002c5c85fe302831c614f17565b6801000000058b90bfce02831c614f0a565b68010000000b17217fbb02831c614efd565b6801000000162e42fff002831c614ef0565b68010000002c5c8601cc02831c614ee3565b680100000058b90c0b4902831c614ed6565b6580000000000083166150af575b65400000000000831661509d575b65200000000000831661508b575b651000000000008316615079575b650800000000008316615067575b650400000000008316615055575b650200000000008316615043575b65010000000000831615614af9576801000000b17218355102831c614af9565b680100000162e430e5a202831c615023565b6801000002c5c863b73f02831c615015565b68010000058b90cf1e6e02831c615007565b680100000b1721bcfc9a02831c614ff9565b68010000162e43f4f83102831c614feb565b680100002c5c89d5ec6d02831c614fdd565b6801000058b91b5bc9ae02831c614fcf565b668000000000000083166151b7575b664000000000000083166151a5575b66200000000000008316615193575b66100000000000008316615181575b6608000000000000831661516f575b6604000000000000831661515d575b6602000000000000831661514b575b6601000000000000831615614aeb5768010000b17255775c0402831c614aeb565b6801000162e525ee054702831c61512a565b68010002c5cc37da949202831c61511b565b680100058ba01fb9f96d02831c61510c565b6801000b175effdc76ba02831c6150fd565b680100162f3904051fa102831c6150ee565b6801002c605e2e8cec5002831c6150df565b68010058c86da1c09ea202831c6150d0565b67800000000000000083166152c7575b67400000000000000083166152b5575b67200000000000000083166152a3575b6710000000000000008316615291575b670800000000000000831661527f575b670400000000000000831661526d575b670200000000000000831661525b575b670100000000000000831615614adc57680100b1afa5abcbed6102831c614adc565b68010163da9fb33356d802831c615239565b680102c9a3e778060ee702831c615229565b6801059b0d31585743ae02831c615219565b68010b5586cf9890f62a02831c615209565b6801172b83c7d517adce02831c6151f9565b6801306fe0a31b7152df02831c6151e9565b5077b504f333f9de6484800000000000000000000000000000006151d9565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091905f19838209838202918280831092039180830392146153b457670de0b6b3a7640000908183101561537d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061540457508051156153da57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061544f575b615415575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561540d56fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a034620003b757601f19906001600160401b0390601f620049bc3881900382810186168401919085831185841017620002d0578085926040948552833981010312620003b75781516001600160a01b038082169490929091859003620003b757602080940151928316809303620003b7576200007b620003bc565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003bc565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002d0576001968754908882811c92168015620003ac575b85831014620002af57818684931162000356575b508490868311600114620002f257600092620002e6575b5050600019600383901b1c191690871b1786555b8751938411620002d0576002548681811c91168015620002c5575b83821014620002af5783811162000263575b5081928411600114620001f65750508192939495600092620001ea575b5050600019600383901b1c191690831b176002555b60018060a01b03198381600054161760005560085416176008556040519160007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145df9081620003dd82396080518161396b0152f35b01519050388062000178565b839291921696600260005282600020926000905b8982106200024b575050838697989695961062000231575b505050811b016002556200018d565b015160001960f88460031b161c1916905538808062000222565b8088859682949686015181550195019301906200020a565b6002600052826000208480870160051c820192858810620002a5575b0160051c019087905b828110620002985750506200015b565b6000815501879062000288565b925081926200027f565b634e487b7160e01b600052602260045260246000fd5b90607f169062000149565b634e487b7160e01b600052604160045260246000fd5b0151905038806200011a565b90848a94169184600052866000209260005b888282106200033f575050841162000325575b505050811b0186556200012e565b015160001960f88460031b161c1916905538808062000317565b8385015186558d9790950194938401930162000304565b90915088600052846000208680850160051c820192878610620003a2575b918b91869594930160051c01915b8281106200039257505062000103565b600081558594508b910162000382565b9250819262000374565b91607f1691620000ef565b600080fd5b60408051919082016001600160401b03811183821017620002d05760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a714612f8a57508063027b674414612f6757806306fdde0314612ea2578063081812fc14612e83578063095ea7b314612d8a5780631400ecec14612cea5780631c1cdd4c14612c855780631e99d56914612c6757806323b872dd14612c4f57806340e58ee5146129bc578063425d30dd1461296b57806342842e0e1461291b57806342966c6814612744578063442675701461271d5780634857501f146126a75780634869e12d1461266c5780634cc55e11146121c457806353b15727146120a557806357404b1214611fda5780636352211e14611faa5780636d0cee7514611faa57806370a0823114611f3a57806375829def14611ea7578063780a82c814611e5a5780637cad6cd114611d605780637de6b1db14611b395780638659c270146117e7578063894e9a0d146114c75780638f69b9931461142b5780639067b677146113db57806395d89b41146112cc578063a22cb4651461120f578063a80fc071146111bd578063ab167ccc14611073578063ad35efd414611011578063b256456914610fc0578063b88d4fde14610f33578063b8a3be6614610efe578063b971302a14610eaf578063bc2be1be14610e5f578063c156a11d1461099a578063c87b56dd1461087e578063d4dbd20b1461082c578063d511609f146107e0578063d975dfed14610794578063e985e9c51461073f578063ea5ead1914610717578063eac8f5b8146106c5578063f590c17614610663578063f851a4401461063d5763fdd46d601461025257600080fd5b3461063a57606036600319011261063a576004359061026f6130b9565b91610278613216565b92610281613961565b818352600960209181835260ff600160408720015460a81c16156106235783855281835260ff600160408720015460a01c1661060b576001600160a01b03958682169283156105f3576001600160801b03938483169081156105db57878952600387528960408a2054169283821415806105cb575b6105a75761030389614148565b87811684116105755750888a5280885260408a20968360028d8a541699015460801c0181811161056157988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103958e96859f8f6040816103909360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b613509565b906103b181868401511692826040818351169201511690613250565b161115610532575b848c528252600160408c20015416946103d3818a88614170565b604051908152a48033141580610528575b6104ba575b8333141590816104af575b816104a4575b5061042e575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610488575b8080610400565b61049190613135565b61049c578238610481565b8280fd5b8380fd5b9050831415386103fa565b843b151591506103f4565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610510575b50506103e9565b61051990613135565b610524578438610509565b8480fd5b50803b15156103e4565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b9565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d5896139bd565b156102f6565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b503461063a578060031936011261063a576001600160a01b036020915416604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a57600435906107356130b9565b9161027881614148565b503461063a57604036600319011261063a576107596130a3565b60406107636130b9565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091614148565b6001600160801b0360405191168152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57604082600292602094526009845220015460801c604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760036040836001600160801b0393602095526009855220015416604051908152f35b503461063a5760208060031936011261098a5760043561089d816136be565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa92831561098e57809361090d575b505061090960405192828493845283019061307e565b0390f35b909192503d8082843e61092081846131d8565b820191838184031261098a5780519067ffffffffffffffff821161049c570182601f8201121561098a57805191610956836131fa565b9361096460405195866131d8565b83855285848401011161063a5750906109829184808501910161305b565b9038806108f3565b5080fd5b604051903d90823e3d90fd5b503461063a57604036600319011261063a576004356109b76130b9565b6109bf613961565b81835260099060209082825260ff600160408720015460a81c161561062357838552600382526001600160a01b03918260408720541693843303610e4057610a0686614148565b906001600160801b039081831680158015610aa6575b50505050505081811615610a8e5783610a3491613820565b90811680610a545760248460405190637e27328960e01b82526004820152fd5b8203610a5e578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610aae613961565b898b5282865260ff600160408d20015460a81c1615610e2957898b5282865260ff600160408d20015460a01c16610e11578815610df957610de157888a52600385528660408b205416918289141580610dd1575b610dad57610b0f8a614148565b8481168311610d7b5750898b5280865260408b20938260028a87541696015460801c01818111610d675790610b768d9796959493928d8952838a52610390600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b92818a8401511692826040818351169201511690613250565b161115610d38575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610bd9818688614170565b604051908152a48033141580610d2e575b610cc4575b813314159081610cb9575b81610cae575b50610c3d575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610a1c565b803b1561049c57604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610c96575b80610c06565b610c9f90613135565b610caa578538610c90565b8580fd5b905081141538610c00565b823b15159150610bfa565b803b156104a057604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610d1a575b5050610bef565b610d2390613135565b6104a0578338610d13565b50803b1515610bea565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610b9a565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610ddb8a6139bd565b15610b02565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae576040826001600160a01b03926020945260098452205416604051908152f35b503461063a57602036600319011261063a5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063a57608036600319011261063a57610f4d6130a3565b610f556130b9565b906064359067ffffffffffffffff82116104a057366023830112156104a05781600401359284610f84856131fa565b93610f9260405195866131d8565b858552366024878301011161098a5785610fbd96602460209301838801378501015260443591613551565b80f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761104a90613799565b60405190600581101561105f57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063a5761014036600319011261063a5761108e613961565b6110966134ea565b9064ffffffffff804216808452816110ac61353d565b166111a7575b60e4359082821682036111a25701166040830152600435916001600160a01b03918284168094036111a257602435908382168092036111a257604435906001600160801b0382168092036111a2576064359085821680920361063a5750608435918215158093036111a25760a435938415158095036111a2576040519761113889613149565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126111a25760405191611172836131bc565b6101043591821682036111a2578261119a9260209452610124358482015260e0820152613aa4565b604051908152f35b600080fd5b816111b061353d565b82011660208501526110b2565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760026040836001600160801b0393602095526009855220015416604051908152f35b503461063a57604036600319011261063a576112296130a3565b602435908115158092036111a2576001600160a01b031690811561129b5733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a578060031936011261063a5760405190806002549160018360011c92600185169485156113d1575b60209586861081146113bd5785885287949392918790821561139b575050600114611341575b505061132d925003836131d8565b61090960405192828493845283019061307e565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061138357505061132d9350820101388061131f565b8054838901850152879450869390920191810161136b565b925093505061132d94915060ff191682840152151560051b820101388061131f565b602483634e487b7160e01b81526022600452fd5b93607f16936112f9565b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5761146490613799565b90600582101590816114a557600283149182156114b9575b8215611490575b6020836040519015158152f35b9091506114a557506004602091143880611483565b80634e487b7160e01b602492526021600452fd5b50600383149150600061147c565b503461063a57602036600319011261063a57806101606040516114e981613182565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261152c6134ea565b61014082015201526004358152600960205260ff600160408320015460a81c16156117cf576004358152600960205260408120906115fa6002604051936115728561319f565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613509565b61012083015261160b600435613799565b60058110156117bb576101606101c093600264ffffffffff93146117b0575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6116b78d613182565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b83606082015261162a565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063a5760208060031936011261098a5760043567ffffffffffffffff811161049c5761181a903690600401613104565b9190611824613961565b83925b808410611832578480f35b61183d8482846134c4565b3593611847613961565b848652600980855260ff600191818360408b20015460a81c1615611b2257878952808752604089208381015460a01c8316156118955760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611b0a576118c68160005260096020526001600160a01b0360406000205416331490565b15611aea576118d4816136e1565b93818a528289526118ea600260408c2001613509565b946001600160801b0394858751168683161015611ad257838c52848b5260408c205460f01c1615611aba57918493918a61193685878f9a99808c9986928d511603169a01511690613250565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a0660408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611aa1575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d20015416946119de8b8588614170565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a4a575b505050505050600101929190611827565b813b15610caa57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611a8d575b80808080611a39565b611a9690613135565b610524578438611a84565b818601600160a01b60ff60a01b1982541617905561199d565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063a5760208060031936011261098a5760043590611b58613961565b8183526009815260ff600160408520015460a81c1615611d4957611b7b82613799565b6005811015611d355760048103611ba45760248360405190634a5541ef60e01b82526004820152fd5b60038103611bc4576024836040519063fe19f19f60e01b82526004820152fd5b600214611d1d57611beb8260005260096020526001600160a01b0360406000205416331490565b15611cfe578183526009815260ff604084205460f01c1615611ce657818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611c8e575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049c57816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611cd2575b80611c5f565b611cdb90613135565b61049c578238611ccc565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461063a57602036600319011261063a576004356001600160a01b039081811680910361049c5781835416338103611e31575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007546000198101908111611e1d5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063a57602036600319011261063a57611ec16130a3565b9080546001600160a01b0380821693338503611f13576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461063a57602036600319011261063a576001600160a01b03611f5c6130a3565b168015611f79578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a57602036600319011261063a576020611fc96004356136be565b6001600160a01b0360405191168152f35b503461063a576020908160031936011261063a5760043591611ffa6134ea565b508282526009815260ff600160408420015460a81c161561208e5760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c16916040519361205585613166565b8452830152604082015261208c60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063a5761016036600319011261063a576120c0613961565b604051906120cd82613149565b6120d56130a3565b82526120df6130b9565b60208301526120ec613216565b60408301526001600160a01b0390606435828116810361098a57606084015260843580151581036111a257608084015260a43580151581036111a25760a084015260603660c319011261063a575060405161214681613166565b64ffffffffff60c43581811681036111a257825260e43581811681036111a25760208301526101043590811681036111a257604082015260c08301526040610123193601126111a2576040519161219c836131bc565b6101243591821682036111a2578261119a9260209452610144358482015260e0820152613aa4565b503461063a57604036600319011261063a5767ffffffffffffffff60043581811161049c576121f7903690600401613104565b90916024359081116104a057612211903690600401613104565b612219613961565b80830361263557845b83811061222d578580f35b6122388185876134c4565b35906122458186886134c4565b35875260036020526001600160a01b036040882054166122668285876134c4565b35906001600160801b03821682036111a257612280613961565b838952600960205260ff600160408b20015460a81c161561062357838952600960205260ff600160408b20015460a01c1661060b57801561261d576001600160801b038216156126055783895260036020526001600160a01b0360408a2054169182821415806125f5575b6125d1576122f885614148565b6001600160801b0381166001600160801b038316116125a15750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161056157906123898c959493928887526009602052610390600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b036123ad8160208401511692826040818351169201511690613250565b161115612570575b86855260096020526001600160a01b036001604087200154166123e26001600160801b0384168583614170565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612566575b6124fc575b8333141590816124f1575b816124e6575b50612474575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612222565b823b156104a057604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124ce575b808061243d565b6124d790613135565b6124e25786386124c7565b8680fd5b905083141538612437565b843b15159150612431565b803b1561052457604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612552575b5050612426565b61255b90613135565b61052457843861254b565b50803b1515612421565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123b5565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125ff856139bd565b156122eb565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b503461063a57602036600319011261063a5760ff6001604060043593848152600960205220015460a81c16156106ae576107cf602091613a26565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611d4957806126e283613799565b9260058410156117bb57600260209403612703575b50506040519015158152f35b815260098352604090205460f01c60ff16905038806126f7565b503461063a578060031936011261063a5760206001600160a01b0360085416604051908152f35b503461063a5760208060031936011261098a5760043590612763613961565b8183526009815260ff600160408520015460a81c1615611d49578183526009815260ff600160408520015460a01c16156128ea576127a0826139bd565b15611cfe5781600052600381526001600160a01b0380604060002054161515806128e2575b806128c8575b6128b0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790836000526003835260406000205416918215928315612875575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a161285d575080f35b60249060405190637e27328960e01b82526004820152fd5b61289685600052600560205260406000206001600160a01b03198154169055565b80600052600482526040600020600019815401905561280b565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c16156127cb565b5060006127c5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063a5761292a366130cf565b60405191602083019383851067ffffffffffffffff86111761295557610fbd94604052858452613551565b634e487b7160e01b600052604160045260246000fd5b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063a576020908160031936011261063a57600435906129dc613961565b818152600980845260ff600160408420015460a81c161561208e5782825280845260408220600181015460a01c60ff1615612a295760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612c3757612a548260005260096020526001600160a01b0360406000205416331490565b15611cfe57612a62826136e1565b93828452818152612a7860026040862001613509565b926001600160801b0391828551168388161015611d1d5781865283815260ff604087205460f01c1615611ce6577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612ae1888584818b9c818c9d9c511603169a01511690613250565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612c1d575b01896001600160801b03198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612b898d8487614170565b8c612bb86040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612bcc578480f35b823b15610524576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c0e575b81818080808480f35b612c1790613135565b38612c05565b60018101600160a01b60ff60a01b19825416179055612b25565b6024826040519063fe19f19f60e01b82526004820152fd5b503461063a57610fbd612c61366130cf565b9161327f565b503461063a578060031936011261063a576020600754604051908152f35b503461063a57602036600319011261063a57600435808252600960205260ff600160408420015460a81c16156106ae57612cbe90613799565b9060058210156114a55760208215838115612cdf575b506040519015158152f35b600191501482612cd4565b503461063a57602036600319011261063a5760043590818152600960205260ff600160408320015460a81c1615611d4957602091604082828152600985522060ff815460f01c1680612d78575b612d4f575b50506001600160801b0360405191168152f35b612d7192506001600160801b036002612d6b92015416916136e1565b90613250565b3880612d3c565b5060ff600182015460a01c1615612d37565b503461063a57604036600319011261063a57612da46130a3565b602435612db0816136be565b33151580612e70575b80612e46575b612e165781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff60408520541615612dbf565b50336001600160a01b0382161415612db9565b503461063a57602036600319011261063a576020611fc960043561322c565b503461063a578060031936011261063a576040519080600191600154928360011c9260018516948515612f5d575b60209586861081146113bd5785885287949392918790821561139b575050600114612f0357505061132d925003836131d8565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b858310612f4557505061132d9350820101388061131f565b80548389018501528794508693909201918101612f2d565b93607f1693612ed0565b503461063a578060031936011261063a57602060405167016345785d8a00008152f35b90503461098a57602036600319011261098a576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361049c57602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613031575b8115613007575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613000565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612ff9565b60005b83811061306e5750506000910152565b818101518382015260200161305e565b906020916130978151809281855285808601910161305b565b601f01601f1916010190565b600435906001600160a01b03821682036111a257565b602435906001600160a01b03821682036111a257565b60609060031901126111a2576001600160a01b039060043582811681036111a2579160243590811681036111a2579060443590565b9181601f840112156111a25782359167ffffffffffffffff83116111a2576020808501948460051b0101116111a257565b67ffffffffffffffff811161295557604052565b610100810190811067ffffffffffffffff82111761295557604052565b6060810190811067ffffffffffffffff82111761295557604052565b610180810190811067ffffffffffffffff82111761295557604052565b610140810190811067ffffffffffffffff82111761295557604052565b6040810190811067ffffffffffffffff82111761295557604052565b90601f8019910116810190811067ffffffffffffffff82111761295557604052565b67ffffffffffffffff811161295557601f01601f191660200190565b604435906001600160801b03821682036111a257565b613235816136be565b5060005260056020526001600160a01b036040600020541690565b6001600160801b03918216908216039190821161326957565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b0380911680156134ac57600091848352602091600383526040928284862054161515806134a4575b8061348c575b6134755786855260038152828486205416948733151593846133c5575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794508761338d575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a18316820361335f5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133ae82600052600560205260406000206001600160a01b03198154169055565b8783526004845286832080546000190190556132fb565b91929380915090613434575b156133df57908783926132d2565b8488876133fc576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503386148015613459575b806133d157508782526005835233848684205416146133d1565b5085825260068352848220338352835260ff858320541661343f565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c16156132b5565b5060016132af565b6024604051633250574960e11b815260006004820152fd5b91908110156134d45760051b0190565b634e487b7160e01b600052603260045260246000fd5b604051906134f782613166565b60006040838281528260208201520152565b9060405161351681613166565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff811681036111a25790565b919061355e82828561327f565b803b61356b575b50505050565b6135c76001600160a01b03809216946040519384937f150b7a020000000000000000000000000000000000000000000000000000000096878652336004870152166024850152604484015260806064840152608483019061307e565b03906020816000938185885af19082908261365d575b505061361457826135ec614118565b805191908261360d5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613645575038808080613565565b60249060405190633250574960e11b82526004820152fd5b909192506020813d6020116136b6575b8161367a602093836131d8565b8101031261098a5751907fffffffff000000000000000000000000000000000000000000000000000000008216820361063a57509038806135dd565b3d915061366d565b8060005260036020526001600160a01b036040600020541690811561285d575090565b600090808252600a60205264ffffffffff918260408220541642106137935760096020526040812092835490808260c81c16918242101561377d576137329394955060a01c16809103904203614314565b9082815260096020526001600160801b03926137588460026040852001541680946143f4565b9283116137655750501690565b60029350604092508152600960205220015460801c90565b505050505060026001600160801b039101541690565b91505090565b806000526009602052604060002060ff600182015460a01c166000146137c0575050600490565b805460f81c613819575460a01c64ffffffffff164210613813576137e3816136e1565b9060005260096020526001600160801b03806002604060002001541691161060001461380e57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613956575b8061393e575b613927579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef848387205416948592836138ef575b1692836138d9575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b83875260048852808720600181540190556138b5565b61391086600052600560205260406000206001600160a01b03198154169055565b8388526004895284882080546000190190556138ad565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c161561384c565b508181161515613846565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361399357565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415613a02575b505082156139f057505090565b9091506139fd339261322c565b161490565b60ff92945090604091815260066020528181203382526020522054169138806139e3565b806000526009602052613a3f6002604060002001613509565b816000526009602052604060002060ff600182015460a01c16600014613a7257506001600160801b039150602001511690565b5460f81c613a875750613a84906136e1565b90565b613a8491506001600160801b036040818351169201511690613250565b90613ac56001600160801b03604084015116602060e08501510151906141cc565b916001600160801b0383511660c082015190156140ee5764ffffffffff815116156140c4576020810164ffffffffff81511680614014575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fd457505064ffffffffff8042169151169081811015613f94575050600754926001600160801b0381511660405190613b5482613166565b815260006020820152600060408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613bb68861319f565b87526020870152604086015260608501526000608085015260a0840152600060c0840152600160e08401526101008301526101208201528460005260096020526040600020906001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b1693171717178255600182016001600160a01b0360a08301511681549074ff000000000000000000000000000000000000000060c0850151151560a01b1675ff00000000000000000000000000000000000000000060e0860151151560a81b16917fffffffffffffffffff000000000000000000000000000000000000000000000076ff00000000000000000000000000000000000000000000610100880151151560b01b1694161717171790556001600160801b03604060036101206002860194015194613dae84875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f76575b50600184016007556001600160a01b0360208301511680156134ac57613dfe856001600160a01b0392613820565b16613f4557613e296001600160a01b036060840151166001600160801b0383511690309033906142a5565b6001600160801b0360208201511680613f16575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613f0d6001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f3f906001600160a01b036060850151166001600160a01b0360e086015151169033906142a5565b38613e3d565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b600a60205260406000209064ffffffffff1982541617905538613dd0565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561408457505064ffffffffff90511664ffffffffff60408301511690818110613afd576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614143573d90614129826131fa565b9161413760405193846131d8565b82523d6000602084013e565b606090565b613a849061415581613a26565b90600052600960205260026040600020015460801c90613250565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ca916141c56064836131d8565b6144a3565b565b919091604051906141dc826131bc565b600091828152826020820152936001600160801b03928383169182156142865767016345785d8a000080821161424f57506142188591846143f4565b166020870192818452111561423b5750908261423692511690613250565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061429a826131bc565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612955576141ca926040526144a3565b670de0b6b3a76400009160001983830992808302928380861095039480860395146143d0578285101561439457908291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143de570490565b634e487b7160e01b600052601260045260246000fd5b9091906000198382098382029182808310920391808303921461449257670de0b6b3a7640000908183101561445b57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b6001600160a01b0316906144ce600080836020829551910182875af16144c7614118565b908461453f565b908151918215159283614517575b5050506144e65750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b81929350906020918101031261098a57602001519081159182150361063a57503880806144dc565b9061457e575080511561455457805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806145c9575b61458f575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561458756fea164736f6c6343000817000a"; + hex"60a0346200039e57601f19906001600160401b0390601f620049713881900382810186168401919085831185841017620002c05780859260409485528339810103126200039e5781516001600160a01b0380821694909290918590036200039e576020809401519283168093036200039e576200007b620003a2565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003a2565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002c0576001968754908882811c9216801562000393575b85831014620002a157818684931162000340575b508490868311600114620002e0575f92620002d4575b50505f19600383901b1c191690871b1786555b8751938411620002c0576002548681811c91168015620002b5575b83821014620002a15783811162000258575b5081928411600114620001ef57505081929394955f92620001e3575b50505f19600383901b1c191690831b176002555b60018060a01b031983815f5416175f556008541617600855604051915f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145ae9081620003c38239608051816139620152f35b015190505f8062000175565b83929192169660025f52825f20925f905b89821062000240575050838697989695961062000227575b505050811b0160025562000189565b01515f1960f88460031b161c191690555f808062000218565b80888596829496860151815501950193019062000200565b60025f52825f208480870160051c82019285881062000297575b0160051c019087905b8281106200028b57505062000159565b5f81550187906200027b565b9250819262000272565b634e487b7160e01b5f52602260045260245ffd5b90607f169062000147565b634e487b7160e01b5f52604160045260245ffd5b015190505f8062000119565b90848a941691845f52865f20925f5b8882821062000329575050841162000310575b505050811b0186556200012c565b01515f1960f88460031b161c191690555f808062000302565b8385015186558d97909501949384019301620002ef565b909150885f52845f208680850160051c82019287861062000389575b918b91869594930160051c01915b8281106200037a57505062000103565b5f81558594508b91016200036a565b925081926200035c565b91607f1691620000ef565b5f80fd5b60408051919082016001600160401b03811183821017620002c05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a714612fb757508063027b674414612f9557806306fdde0314612e9f578063081812fc14612e81578063095ea7b314612d885780631400ecec14612ce85780631c1cdd4c14612c705780631e99d56914612c5357806323b872dd14612c3a57806340e58ee51461299e578063425d30dd1461294d57806342842e0e146128ff57806342966c6814612736578063442675701461270f5780634857501f146126995780634869e12d1461265e5780634cc55e11146121b657806353b157271461209757806357404b1214611fcc5780636352211e14611f9c5780636d0cee7514611f9c57806370a0823114611f2c57806375829def14611e99578063780a82c814611e4c5780637cad6cd114611d535780637de6b1db14611b2e5780638659c270146117de578063894e9a0d146114be5780638f69b993146114235780639067b677146113d357806395d89b41146112c4578063a22cb46514611209578063a80fc071146111b7578063ab167ccc1461106e578063ad35efd41461100c578063b256456914610fbb578063b88d4fde14610f2e578063b8a3be6614610ef9578063b971302a14610eaa578063bc2be1be14610e5a578063c156a11d14610995578063c87b56dd14610879578063d4dbd20b14610827578063d511609f146107db578063d975dfed1461078f578063e985e9c51461073c578063ea5ead1914610714578063eac8f5b8146106c2578063f590c17614610660578063f851a4401461063a5763fdd46d601461024f575f80fd5b34610637576060366003190112610637576004359061026c6130e2565b9161027561323f565b9261027e613958565b818352600960209181835260ff600160408720015460a81c16156106205783855281835260ff600160408720015460a01c16610608576001600160a01b03958682169283156105f0576001600160801b03938483169081156105d857878952600387528960408a2054169283821415806105c8575b6105a4576103008961412d565b87811684116105725750888a5280885260408a20968360028d8a541699015460801c0181811161055e57988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103928e96859f8f60408161038d9360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b61351d565b906103ae81868401511692826040818351169201511690613277565b16111561052f575b848c528252600160408c20015416946103d0818a88614153565b604051908152a48033141580610525575b6104b7575b8333141590816104ac575b816104a1575b5061042b575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b1561049d57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610485575b80806103fd565b61048e9061315e565b61049957825f61047e565b8280fd5b8380fd5b90508314155f6103f7565b843b151591506103f1565b803b1561052157604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161050d575b50506103e6565b6105169061315e565b61052157845f610506565b8480fd5b50803b15156103e1565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b6565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d2896139b4565b156102f3565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b50346106375780600319360112610637576001600160a01b036020915416604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063757604036600319011261063757600435906107326130e2565b916102758161412d565b5034610637576040366003190112610637576107566130cc565b60406107606130e2565b926001600160a01b03809316815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346106375760203660031901126106375760ff6001604060043593848152600960205220015460a81c16156106ab576107ca60209161412d565b6001600160801b0360405191168152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57604082600292602094526009845220015460801c604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760036040836001600160801b0393602095526009855220015416604051908152f35b50346106375760208060031936011261098557600435610898816136cc565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610989578093610908575b50506109046040519282849384528301906130a7565b0390f35b909192503d8082843e61091b8184613201565b82019183818403126109855780519067ffffffffffffffff8211610499570182601f820112156109855780519161095183613223565b9361095f6040519586613201565b83855285848401011161063757509061097d91848085019101613086565b905f806108ee565b5080fd5b604051903d90823e3d90fd5b5034610637576040366003190112610637576004356109b26130e2565b6109ba613958565b81835260099060209082825260ff600160408720015460a81c161561062057838552600382526001600160a01b03918260408720541693843303610e3b57610a018661412d565b906001600160801b039081831680158015610aa1575b50505050505081811615610a895783610a2f9161381d565b90811680610a4f5760248460405190637e27328960e01b82526004820152fd5b8203610a59578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610aa9613958565b898b5282865260ff600160408d20015460a81c1615610e2457898b5282865260ff600160408d20015460a01c16610e0c578815610df457610ddc57888a52600385528660408b205416918289141580610dcc575b610da857610b0a8a61412d565b8481168311610d765750898b5280865260408b20938260028a87541696015460801c01818111610d625790610b718d9796959493928d8952838a5261038d600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b8d818a8401511692826040818351169201511690613277565b161115610d33575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610bd4818688614153565b604051908152a48033141580610d29575b610cbf575b813314159081610cb4575b81610ca9575b50610c38575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a15f8080808080610a17565b803b1561049957604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610c91575b80610c01565b610c9a9061315e565b610ca557855f610c8b565b8580fd5b90508114155f610bfb565b823b15159150610bf5565b803b1561049d57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610d15575b5050610bea565b610d1e9061315e565b61049d57835f610d0e565b50803b1515610be5565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610b95565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610dd68a6139b4565b15610afd565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab576040826001600160a01b03926020945260098452205416604051908152f35b50346106375760203660031901126106375760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063757608036600319011261063757610f486130cc565b610f506130e2565b906064359067ffffffffffffffff821161049d573660238301121561049d5781600401359284610f7f85613223565b93610f8d6040519586613201565b85855236602487830101116109855785610fb896602460209301838801378501015260443591613565565b80f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab576110459061379d565b60405190600581101561105a57602092508152f35b602483634e487b7160e01b81526021600452fd5b50346106375761014036600319011261063757611089613958565b6110916134ff565b9064ffffffffff804216808452816110a7613551565b166111a1575b60e43590828216820361119d5701166040830152600435916001600160a01b039182841680940361119d576024359083821680920361119d57604435906001600160801b03821680920361119d576064359085821680920361063757506084359182151580930361119d5760a4359384151580950361119d576040519761113389613172565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261119d576040519161116d836131e5565b61010435918216820361119d57826111959260209452610124358482015260e0820152613a92565b604051908152f35b5f80fd5b816111aa613551565b82011660208501526110ad565b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760026040836001600160801b0393602095526009855220015416604051908152f35b5034610637576040366003190112610637576112236130cc565b6024359081151580920361119d576001600160a01b031690811561129357338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063757806003193601126106375760405190806002549160018360011c92600185169485156113c9575b60209586861081146113b557858852879493929187908215611393575050600114611339575b505061132592500383613201565b6109046040519282849384528301906130a7565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061137b57505061132593508201015f80611317565b80548389018501528794508693909201918101611363565b925093505061132594915060ff191682840152151560051b8201015f80611317565b602483634e487b7160e01b81526022600452fd5b93607f16936112f1565b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5761145c9061379d565b906005821015908161149d57600283149182156114b1575b8215611488575b6020836040519015158152f35b90915061149d57506004602091145f8061147b565b80634e487b7160e01b602492526021600452fd5b506003831491505f611474565b503461063757602036600319011261063757806101606040516114e0816131ab565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115236134ff565b61014082015201526004358152600960205260ff600160408320015460a81c16156117c6576004358152600960205260408120906115f1600260405193611569856131c8565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161351d565b61012083015261160260043561379d565b60058110156117b2576101606101c093600264ffffffffff93146117a7575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6116ae8d6131ab565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b836060820152611621565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b5034610637576020806003193601126109855760043567ffffffffffffffff81116104995761181190369060040161312d565b919061181b613958565b83925b808410611829578480f35b6118348482846134db565b359361183e613958565b848652600980855260ff600191818360408b20015460a81c1615611b1757878952808752604089208381015460a01c83161561188c5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611aff576118bb815f5260096020526001600160a01b0360405f205416331490565b15611adf576118c9816136ed565b93818a528289526118df600260408c200161351d565b946001600160801b0394858751168683161015611ac757838c52848b5260408c205460f01c1615611aaf57918493918a61192b85878f9a99808c9986928d511603169a01511690613277565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506119fb60408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611a96575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d20015416946119d38b8588614153565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a3f575b50505050505060010192919061181e565b813b15610ca557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611a82575b80808080611a2e565b611a8b9061315e565b61052157845f611a79565b818601600160a01b60ff60a01b19825416179055611992565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b5034610637576020806003193601126109855760043590611b4d613958565b8183526009815260ff600160408520015460a81c1615611d3c57611b708261379d565b6005811015611d285760048103611b995760248360405190634a5541ef60e01b82526004820152fd5b60038103611bb9576024836040519063fe19f19f60e01b82526004820152fd5b600214611d1057611bde825f5260096020526001600160a01b0360405f205416331490565b15611cf1578183526009815260ff604084205460f01c1615611cd957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611c81575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049957816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611cc5575b80611c52565b611cce9061315e565b61049957825f611cbf565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610637576020366003190112610637576004356001600160a01b03908181168091036104995781835416338103611e23575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e0f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063757602036600319011261063757611eb36130cc565b9080546001600160a01b0380821693338503611f05576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610637576020366003190112610637576001600160a01b03611f4e6130cc565b168015611f6b578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610637576020366003190112610637576020611fbb6004356136cc565b6001600160a01b0360405191168152f35b503461063757602090816003193601126106375760043591611fec6134ff565b508282526009815260ff600160408420015460a81c16156120805760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c1691604051936120478561318f565b8452830152604082015261207e60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063757610160366003190112610637576120b2613958565b604051906120bf82613172565b6120c76130cc565b82526120d16130e2565b60208301526120de61323f565b60408301526001600160a01b03906064358281168103610985576060840152608435801515810361119d57608084015260a435801515810361119d5760a084015260603660c319011261063757506040516121388161318f565b64ffffffffff60c435818116810361119d57825260e435818116810361119d57602083015261010435908116810361119d57604082015260c083015260406101231936011261119d576040519161218e836131e5565b61012435918216820361119d57826111959260209452610144358482015260e0820152613a92565b50346106375760403660031901126106375767ffffffffffffffff600435818111610499576121e990369060040161312d565b909160243590811161049d5761220390369060040161312d565b61220b613958565b80830361262757845b83811061221f578580f35b61222a8185876134db565b35906122378186886134db565b35875260036020526001600160a01b036040882054166122588285876134db565b35906001600160801b038216820361119d57612272613958565b838952600960205260ff600160408b20015460a81c161561062057838952600960205260ff600160408b20015460a01c1661060857801561260f576001600160801b038216156125f75783895260036020526001600160a01b0360408a2054169182821415806125e7575b6125c3576122ea8561412d565b6001600160801b0381166001600160801b038316116125935750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161055e579061237b8c95949392888752600960205261038d600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361239f8160208401511692826040818351169201511690613277565b161115612562575b86855260096020526001600160a01b036001604087200154166123d46001600160801b0384168583614153565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612558575b6124ee575b8333141590816124e3575b816124d8575b50612466575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612214565b823b1561049d57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c0575b808061242f565b6124c99061315e565b6124d457865f6124b9565b8680fd5b90508314155f612429565b843b15159150612423565b803b1561052157604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612544575b5050612418565b61254d9061315e565b61052157845f61253d565b50803b1515612413565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123a7565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f1856139b4565b156122dd565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106375760203660031901126106375760ff6001604060043593848152600960205220015460a81c16156106ab576107ca602091613a19565b50346106375760203660031901126106375760043590818152600960205260ff600160408320015460a81c1615611d3c57806126d48361379d565b9260058410156117b2576002602094036126f5575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f806126e9565b503461063757806003193601126106375760206001600160a01b0360085416604051908152f35b5034610637576020806003193601126109855760043590612755613958565b8183526009815260ff600160408520015460a81c1615611d3c578183526009815260ff600160408520015460a01c16156128ce57612792826139b4565b15611cf157815f52600381526001600160a01b038060405f2054161515806128c7575b806128ae575b612896577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f205416918215928315612860575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612848575080f35b60249060405190637e27328960e01b82526004820152fd5b61287f855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f1981540190556127f9565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c16156127bb565b505f6127b5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106375761290e366130f8565b60405191602083019383851067ffffffffffffffff86111761293957610fb894604052858452613565565b634e487b7160e01b5f52604160045260245ffd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461119d5760208060031936011261119d57600435906129bd613958565b815f52600980825260ff600160405f20015460a81c161561208057825f5280825260405f2060ff600182015460a01c165f14612a0b5760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612c2257612a31835f5260096020526001600160a01b0360405f205416331490565b15612c0357612a3f836136ed565b835f52818352612a54600260405f200161351d565b936001600160801b0391828651168382161015611d1057815f5283855260ff60405f205460f01c1615611cd957612aba818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c511603169901511690613277565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88161789558216978815612be9575b01886001600160801b03198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f2001541693612b628c8487614153565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b612b96578580f35b813b1561119d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bd8575b808080808580f35b612be2915061315e565b5f80612bd0565b60018101600160a01b60ff60a01b19825416179055612afe565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b3461119d57612c51612c4b366130f8565b916132a4565b005b3461119d575f36600319011261119d576020600754604051908152f35b3461119d57602036600319011261119d57600435805f52600960205260ff600160405f20015460a81c16156106ab57612ca89061379d565b6005811015612cd4578060209115908115612cc9575b506040519015158152f35b600191501482612cbe565b634e487b7160e01b5f52602160045260245ffd5b3461119d57602036600319011261119d57600435805f52600960205260ff600160405f20015460a81c16156106ab576020905f90805f526009835260405f2060ff815460f01c1680612d76575b612d4d575b50506001600160801b0360405191168152f35b612d6f92506001600160801b036002612d6992015416916136ed565b90613277565b8280612d3a565b5060ff600182015460a01c1615612d35565b3461119d57604036600319011261119d57612da16130cc565b602435612dad816136cc565b33151580612e6e575b80612e44575b612e145781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f20541615612dbc565b50336001600160a01b0382161415612db6565b3461119d57602036600319011261119d576020611fbb600435613255565b3461119d575f36600319011261119d576040515f600190600154918260011c9160018416918215612f8b575b6020948585108414612f775785879486865291825f14612f57575050600114612efc575b5061132592500383613201565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b858310612f3f575050611325935082010185612eef565b80548389018501528794508693909201918101612f28565b60ff19168582015261132595151560051b8501019250879150612eef9050565b634e487b7160e01b5f52602260045260245ffd5b92607f1692612ecb565b3461119d575f36600319011261119d57602060405167016345785d8a00008152f35b3461119d57602036600319011261119d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361119d57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561305c575b8115613032575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361302b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613024565b5f5b8381106130975750505f910152565b8181015183820152602001613088565b906020916130c081518092818552858086019101613086565b601f01601f1916010190565b600435906001600160a01b038216820361119d57565b602435906001600160a01b038216820361119d57565b606090600319011261119d576001600160a01b0390600435828116810361119d5791602435908116810361119d579060443590565b9181601f8401121561119d5782359167ffffffffffffffff831161119d576020808501948460051b01011161119d57565b67ffffffffffffffff811161293957604052565b610100810190811067ffffffffffffffff82111761293957604052565b6060810190811067ffffffffffffffff82111761293957604052565b610180810190811067ffffffffffffffff82111761293957604052565b610140810190811067ffffffffffffffff82111761293957604052565b6040810190811067ffffffffffffffff82111761293957604052565b90601f8019910116810190811067ffffffffffffffff82111761293957604052565b67ffffffffffffffff811161293957601f01601f191660200190565b604435906001600160801b038216820361119d57565b61325e816136cc565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b03918216908216039190821161329057565b634e487b7160e01b5f52601160045260245ffd5b906001600160a01b038091169081156134c457835f526020906003825260409181835f2054161515806134bc575b806134a4575b61348d57855f526003815281835f20541693331515806133e6575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856133b1575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036133835750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133d0885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f19815401905561331d565b8061344c575b156133f7575f6132f3565b838786613414576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503385148015613471575b806133ec5750865f52600582523383855f205416146133ec565b50845f5260068252835f20335f52825260ff845f205416613457565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c16156132d8565b5060016132d2565b6024604051633250574960e11b81525f6004820152fd5b91908110156134eb5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061350c8261318f565b5f6040838281528260208201520152565b9060405161352a8161318f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361119d5790565b919290926135748185856132a4565b833b613581575b50505050565b6020906001600160a01b03809516946135e260405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906130a7565b03815f875af15f918161366f575b5061362657826135fe6140fe565b805191908261361f5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361365757505f80808061357b565b60249060405190633250574960e11b82526004820152fd5b9091506020813d6020116136c4575b8161368b60209383613201565b8101031261119d57517fffffffff000000000000000000000000000000000000000000000000000000008116810361119d57905f6135f0565b3d915061367e565b805f5260036020526001600160a01b0360405f205416908115612848575090565b805f52600a60205264ffffffffff908160405f205416421061379757600960205260405f2091825490808260c81c1691824210156137835761373a93945060a01c168091039042036142f0565b815f5260096020526001600160801b039161375f83600260405f2001541680936143cc565b91821161376b57501690565b9150505f526009602052600260405f20015460801c90565b50505050600201546001600160801b031690565b50505f90565b805f52600960205260405f2060ff600182015460a01c165f146137c1575050600490565b805460f81c613816575460a01c64ffffffffff164210613811576137e4816136ed565b905f5260096020526001600160801b0380600260405f200154169116105f1461380c57600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f20541615158061394d575b80613935575b61391e578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f20541692836138e9575b1692836138d3575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f206001815401905561388c565b613908835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613884565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613847565b508581161515613841565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398a57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f205416918233149283156139f6575b5082156139e457505090565b9091506139f13392613255565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f6139d8565b805f526009602052613a30600260405f200161351d565b815f52600960205260405f2060ff600182015460a01c165f14613a6057506001600160801b039150602001511690565b5460f81c613a755750613a72906136ed565b90565b613a7291506001600160801b036040818351169201511690613277565b90613ab36001600160801b03604084015116602060e08501510151906141af565b916001600160801b0383511660c082015190156140d45764ffffffffff815116156140aa576020810164ffffffffff81511680613ffa575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fba57505064ffffffffff8042169151169081811015613f7a575050600754926001600160801b0381511660405190613b428261318f565b81525f60208201525f60408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613ba2886131c8565b87526020870152604086015260608501525f608085015260a08401525f60c0840152600160e08401526101008301526101208201908152855f52600960205260405f20916001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b169317171717835560018301906001600160a01b0360a0820151169082549174ff000000000000000000000000000000000000000060c0830151151560a01b16907fffffffffffffffffff000000000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000061010075ff00000000000000000000000000000000000000000060e0870151151560a81b16950151151560b01b1694161717171790556001600160801b036040600360028501935194613d9684875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f5d575b50600184016007556001600160a01b0360208301511680156134c457613de6856001600160a01b039261381d565b16613f2d57613e116001600160a01b036060840151166001600160801b038351169030903390614281565b6001600160801b0360208201511680613efe575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613ef56001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f27906001600160a01b036060850151166001600160a01b0360e08601515116903390614281565b5f613e25565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b600a60205260405f209064ffffffffff198254161790555f613db8565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561406a57505064ffffffffff90511664ffffffffff60408301511690818110613aeb576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614128573d9061410f82613223565b9161411d6040519384613201565b82523d5f602084013e565b606090565b613a729061413a81613a19565b905f526009602052600260405f20015460801c90613277565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ad916141a8606483613201565b61447a565b565b9190916040516141be816131e5565b5f81525f6020820152926001600160801b03918281169182156142635767016345785d8a000080821161422c57506141f78491846143cc565b1660208601928184521115614218578261421392511690613277565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050509050604051614275816131e5565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612939576141ad9260405261447a565b670de0b6b3a7640000915f1983830992808302928380861095039480860395146143aa578285101561436e579082910960018219018216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143b8570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461446957670de0b6b3a7640000908183101561443257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036144a393169360208151910182865af161449c6140fe565b908361450e565b80519081151591826144ea575b50506144b95750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261119d576020015180159081150361119d575f806144b0565b9061454d575080511561452357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614598575b61455e575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561455656fea164736f6c6343000817000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003dc576001600160401b0390601f601f1962004e3a3881900383810183168501919086831186841017620002f557808692606094604052833981010312620003dc5782516001600160a01b038082169590929091869003620003dc5760209485810151938416809403620003dc57604001519362000081620003e1565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003e1565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002f5576001988954908a82811c92168015620003d1575b84831014620002d45781868493116200037b575b50839086831160011462000317576000926200030b575b5050600019600383901b1c191690891b1788555b8151948511620002f557600254938885811c95168015620002ea575b82861014620002d457848487961162000277575b50819385116001146200020d57505060009262000201575b5050600019600383901b1c191690841b176002555b60018060a01b03198481600054161760005560085416176008556040519260007fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a38908162000402823960805181613e1a015260a051818181612f2f0152613ec00152f35b0151905038806200017c565b88959392919316600260005283600020936000905b8282106200025d575050841162000243575b505050811b0160025562000191565b015160001960f88460031b161c1916905538808062000234565b8484015186558a9790950194938401939081019062000222565b9091929394506002600052826000208580880160051c820192858910620002ca575b9188978c9297969594930160051c01915b828110620002ba57505062000164565b600081558897508b9101620002aa565b9250819262000299565b634e487b7160e01b600052602260045260246000fd5b94607f169462000150565b634e487b7160e01b600052604160045260246000fd5b01519050388062000120565b90878c94169184600052856000209260005b878282106200036457505084116200034a575b505050811b01885562000134565b015160001960f88460031b161c191690553880806200033c565b8385015186558f9790950194938401930162000329565b9091508a600052836000208680850160051c820192868610620003c7575b918d91869594930160051c01915b828110620003b757505062000109565b600081558594508d9101620003a7565b9250819262000399565b91607f1691620000f5565b600080fd5b60408051919082016001600160401b03811183821017620002f55760405256fe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461328d57508063027b67441461326a57806306fdde03146131a5578063081812fc14613186578063095ea7b31461308d5780631400ecec14612fed5780631c1cdd4c14612f885780631e99d56914612f6a57806323b872dd14612f525780632fe4304114612f1757806332fbe22b14612dbf57806340e58ee514612b0c578063425d30dd14612abb57806342842e0e14612a8157806342966c68146128aa57806344267570146128835780634857501f1461280d5780634869e12d146127d25780634cc55e111461230f57806357404b12146122775780636352211e146122475780636d0cee751461224757806370a08231146121d757806375829def146121445780637cad6cd11461204a5780637de6b1db14611e235780637f5799f914611dc85780638659c27014611a6d578063894e9a0d146116e1578063897f362b146114315780638f69b993146113955780639067b6771461134557806395d89b4114611236578063a22cb46514611179578063a80fc07114611127578063ad35efd4146110c5578063b256456914611074578063b88d4fde14610fe7578063b8a3be6614610fb2578063b971302a14610f63578063bc2be1be14610f13578063c156a11d14610a64578063c87b56dd14610948578063d4dbd20b146108f6578063d511609f146108aa578063d975dfed1461085e578063e985e9c514610809578063ea5ead191461070f578063eac8f5b8146106bd578063f590c1761461065b578063f851a440146106355763fdd46d601461025d57600080fd5b34610632576060366003190112610632576004359061027a6133bc565b91604435926001600160801b038085169182860361062d5761029a613e10565b83855260099560209387855260ff600160408920015460a81c16156106165785875287855260ff600160408920015460a01c166105fe576001600160a01b039081841680156105e65781156105ce57878952600387528260408a2054169283821415806105be575b61059a5761030f8961466b565b8781168411610568575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c9061034391614693565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff191691161781556103799061395f565b90808483015116918180825116916040015116610395916135a4565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610539575b848c528252600160408c20015416946103da818a886147f8565b604051908152a4803314158061052f575b6104c1575b8333141590816104b6575b816104ab575b50610435575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048f575b8080610407565b610498906134c5565b6104a3578238610488565b8280fd5b8380fd5b905083141538610401565b843b151591506103fb565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610517575b50506103f0565b610520906134c5565b61052b578438610510565b8480fd5b50803b15156103eb565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103c0565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c889614554565b15610302565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b600080fd5b80fd5b50346106325780600319360112610632576001600160a01b036020915416604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760016040836001600160a01b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576004359061072d6133bc565b916107378161466b565b92610740613e10565b81835260099360209185835260ff600160408720015460a81c16156107f25783855285835260ff600160408720015460a01c166107da576001600160a01b03918282169283156107c2576001600160801b03938483169081156105ce57878952600387528260408a2054169283821415806105be5761059a5761030f8961466b565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b5034610632576040366003190112610632576108236133a6565b604061082d6133bc565b926001600160a01b0380931681526006602052209116600052602052602060ff604060002054166040519015158152f35b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a65761089960209161466b565b6001600160801b0360405191168152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082600292602094526009845220015460801c604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760036040836001600160801b0393602095526009855220015416604051908152f35b503461063257602080600319360112610a545760043561096781613b21565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a585780936109d7575b50506109d3604051928284938452830190613381565b0390f35b909192503d8082843e6109ea818461352e565b8201918381840312610a545780519067ffffffffffffffff82116104a3570182601f82011215610a5457805191610a2083613550565b93610a2e604051958661352e565b838552858484010111610632575090610a4c9184808501910161335e565b9038806109bd565b5080fd5b604051903d90823e3d90fd5b503461063257604036600319011261063257600435610a816133bc565b610a89613e10565b81835260099060209082825260ff600160408720015460a81c16156107f257838552600382526001600160a01b03918260408720541693843303610ef457610ad08661466b565b906001600160801b039081831680158015610b70575b50505050505081811615610b585783610afe91613ccf565b90811680610b1e5760248460405190637e27328960e01b82526004820152fd5b8203610b28578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b78613e10565b898b5282865260ff600160408d20015460a81c1615610edd57898b5282865260ff600160408d20015460a01c16610ec5578815610ead57610e9557888a52600385528660408b205416918289141580610e85575b610e6157610bd98a61466b565b8481168311610e2f5750908a949392918a86528087526040862093610c3e610c0c8760028d89541698015460801c614693565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b16911617815561395f565b90610c5a818a84015116928260408183511692015116906135a4565b161115610e00575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610ca18186886147f8565b604051908152a48033141580610df6575b610d8c575b813314159081610d81575b81610d76575b50610d05575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a1388080808080610ae6565b803b156104a357604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d5e575b80610cce565b610d67906134c5565b610d72578538610d58565b8580fd5b905081141538610cc8565b823b15159150610cc2565b803b156104a757604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610de2575b5050610cb7565b610deb906134c5565b6104a7578338610ddb565b50803b1515610cb2565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c62565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610e8f8a614554565b15610bcc565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576040826001600160a01b03926020945260098452205416604051908152f35b50346106325760203660031901126106325760ff6001604060209360043581526009855220015460a81c166040519015158152f35b5034610632576080366003190112610632576110016133a6565b6110096133bc565b906064359067ffffffffffffffff82116104a757366023830112156104a7578160040135928461103885613550565b93611046604051958661352e565b8585523660248783010111610a545785611071966024602093018388013785010152604435916139b4565b80f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576110fe90613c48565b60405190600581101561111357602092508152f35b602483634e487b7160e01b81526021600452fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760026040836001600160801b0393602095526009855220015416604051908152f35b5034610632576040366003190112610632576111936133a6565b6024359081151580920361062d576001600160a01b03169081156112055733835260066020526040832082600052602052604060002060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257806003193601126106325760405190806002549160018360011c926001851694851561133b575b6020958686108114611327578588528794939291879082156113055750506001146112ab575b50506112979250038361352e565b6109d3604051928284938452830190613381565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106112ed57505061129793508201013880611289565b805483890185015287945086939092019181016112d5565b925093505061129794915060ff191682840152151560051b8201013880611289565b602483634e487b7160e01b81526022600452fd5b93607f1693611263565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a65760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a6576113ce90613c48565b906005821015908161140f5760028314918215611423575b82156113fa575b6020836040519015158152f35b90915061140f575060046020911438806113ed565b80634e487b7160e01b602492526021600452fd5b5060038314915060006113e6565b5034610632576020906003198281360112610a54576004359167ffffffffffffffff91828411610a545761012084360391820112610a5457611471613e10565b60c48401359060221901811215610a545783016004810135928311610a545760248101908360061b80360383136104a7576024906114ae8661382a565b956114bc604051978861352e565b8652878601920101913683116104a757905b868383106116c957505050508151906114e68261382a565b926114f4604051948561352e565b828452601f196115038461382a565b0186835b8281106116a55750505064ffffffffff804216936001600160801b03928361152e82613b44565b51511683808b61153d85613b44565b5101511688011660405191611551836134d9565b82528a82015261156088613b44565b5261156a87613b44565b5060019260015b83811061163c57505050505061158985600401613993565b9161159660248701613993565b916115a3604488016138cd565b6064880135926001600160a01b03908185168095036106325750928895926115f498959261162998956115db60846116349d016139a7565b94816115e960a48c016139a7565b976040519d8e6134a8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613878565b610100820152613e6c565b604051908152f35b8089838d8180826116618d6116528e9a8d613b51565b51511696600019890190613b51565b5101511691611670868a613b51565b51015116011660405191611683836134d9565b82528d820152611693828c613b51565b5261169e818b613b51565b5001611571565b6040516116b1816134d9565b60008152600083820152828289010152018790611507565b6040916116d63685613842565b8152019101906114ce565b5034610632576020366003190112610632576060610160604051611704816134f5565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201528361012082015260405161174a81613512565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611a555760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a3f5761183b9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161395f565b61012083015261184c600435613c48565b6005811015611a2b57610160926118f79260026119339314611a20575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e6134f5565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138e1565b828201526109d3604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061344c565b806060830152611869565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b600052604160045260246000fd5b602460405162b8e7e760e51b81526004356004820152fd5b503461063257602080600319360112610a545760043567ffffffffffffffff81116104a357611aa090369060040161341b565b9190611aaa613e10565b83925b808410611ab8578480f35b611ac38482846138a7565b3593611acd613e10565b848652600980855260ff600191818360408b20015460a81c1615611db157878952808752604089208381015460a01c831615611b1b5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d9957611b4c8160005260096020526001600160a01b0360406000205416331490565b15611d7957611b5a81613b65565b93818a52828952611b70600260408c200161395f565b946001600160801b0394858751168683161015611d6157838c52848b5260408c205460f01c1615611d4957918493918a611bbc85878f9a99808c9986928d511603169a015116906135a4565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611c9560408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611d30575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611c6d8b85886147f8565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611cd9575b505050505050600101929190611aad565b813b15610d7257856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d1c575b80808080611cc8565b611d25906134c5565b61052b578438611d13565b818601600160a01b60ff60a01b19825416179055611c23565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657604082611e0f926109d39452600a602052206138e1565b60405191829160208352602083019061344c565b503461063257602080600319360112610a545760043590611e42613e10565b8183526009815260ff600160408520015460a81c161561203357611e6582613c48565b600581101561201f5760048103611e8e5760248360405190634a5541ef60e01b82526004820152fd5b60038103611eae576024836040519063fe19f19f60e01b82526004820152fd5b60021461200757611ed58260005260096020526001600160a01b0360406000205416331490565b15611fe8578183526009815260ff604084205460f01c1615611fd057818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611f78575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a357816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611fbc575b80611f49565b611fc5906134c5565b6104a3578238611fb6565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610632576020366003190112610632576004356001600160a01b03908181168091036104a3578183541633810361211b575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a260075460001981019081116121075760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b50346106325760203660031901126106325761215e6133a6565b9080546001600160a01b03808216933385036121b0576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610632576020366003190112610632576001600160a01b036121f96133a6565b168015612216578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610632576020366003190112610632576020612266600435613b21565b6001600160a01b0360405191168152f35b5034610632576020366003190112610632576004356000602060405161229c816134d9565b8281520152808252600960205260ff600160408420015460a81c16156106a657604082819281526009602052205464ffffffffff8251916122dc836134d9565b818160a01c16835260c81c16602082015261230d825180926020908164ffffffffff91828151168552015116910152565bf35b50346106325760403660031901126106325767ffffffffffffffff6004358181116104a35761234290369060040161341b565b9091602490813590811161052b5761235e90369060040161341b565b612369929192613e10565b80840361279c57855b84811061237d578680f35b6123888186886138a7565b35906123958187896138a7565b35885260036020526001600160a01b036040892054166123be6123b98386896138a7565b6138cd565b906123c7613e10565b838a52600960205260ff600160408c20015460a81c161561278657838a52600960205260ff600160408c20015460a01c1661276f578015612758576001600160801b0382161561274157838a5260036020526001600160a01b0360408b205416918282141580612731575b61270d5761243f8561466b565b6001600160801b0381166001600160801b038316116126dd5750908a9291858452600960205260408420926124c56001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff196124a787608094851c614693565b938c8b52600960205260408b2001938454931b16911617815561395f565b6001600160801b036124e981602084015116928260408183511692015116906135a4565b1611156126ac575b86855260096020526001600160a01b0360016040872001541661251e6001600160801b03841685836147f8565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a480331415806126a2575b612638575b83331415908161262d575b81612622575b506125b0575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612372565b823b156104a757604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161260a575b8080612579565b612613906134c5565b61261e578738612603565b8780fd5b905083141538612573565b843b1515915061256d565b803b1561052b57604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161268e575b5050612562565b612697906134c5565b61052b578438612687565b50803b151561255d565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124f1565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061273b85614554565b15612432565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b50346106325760203660031901126106325760ff6001604060043593848152600960205220015460a81c16156106a6576108996020916145bd565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c1615612033578061284883613c48565b926005841015611a2b57600260209403612869575b50506040519015158152f35b815260098352604090205460f01c60ff169050388061285d565b503461063257806003193601126106325760206001600160a01b0360085416604051908152f35b503461063257602080600319360112610a5457600435906128c9613e10565b8183526009815260ff600160408520015460a81c1615612033578183526009815260ff600160408520015460a01c1615612a505761290682614554565b15611fe85781600052600381526001600160a01b038060406000205416151580612a48575b80612a2e575b612a16577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7908360005260038352604060002054169182159283156129db575b846000526003825260406000206001600160a01b03198154169055846000604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129c3575080f35b60249060405190637e27328960e01b82526004820152fd5b6129fc85600052600560205260406000206001600160a01b03198154169055565b806000526004825260406000206000198154019055612971565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff60016040600020015460b01c1615612931565b50600061292b565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063257612a90366133e6565b60405191602083019383851067ffffffffffffffff861117611a3f57611071946040528584526139b4565b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657600160408360ff93602095526009855220015460a01c166040519015158152f35b503461063257602090816003193601126106325760043590612b2c613e10565b818152600980845260ff600160408420015460a81c1615612da85782825280845260408220600181015460a01c60ff1615612b795760248460405190634a5541ef60e01b82526004820152fd5b9291925460f81c612d9057612ba48260005260096020526001600160a01b0360406000205416331490565b15611fe857612bb282613b65565b93828452818152612bc86002604086200161395f565b926001600160801b03918285511683881610156120075781865283815260ff604087205460f01c1615611fd0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7612c31888584818b9c818c9d9c511603169a015116906135a4565b9183875285815260408720926003845496600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89161786558216948515612d76575b01896fffffffffffffffffffffffffffffffff198254161790556001600160a01b038096169660038352877f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508860408c2054169889938652600160408d2001541693612ce28d84876147f8565b8c612d116040519283928c84916040919493606084019584526001600160801b03809216602085015216910152565b0390a4604051848152a1823b612d25578480f35b823b1561052b576084928591604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d67575b81818080808480f35b612d70906134c5565b38612d5e565b60018101600160a01b60ff60a01b19825416179055612c75565b6024826040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b5034610632576003199060203683018113610a54576004359167ffffffffffffffff93848411610a545761014090843603011261063257612dfe613e10565b60405193612e0b856134a8565b612e17846004016133d2565b8552612e25602485016133d2565b6020860152612e366044850161356c565b604086015260648401356001600160a01b03811681036104a3576060860152612e616084850161349b565b6080860152612e7260a4850161349b565b60a0860152612e8360c48501613818565b60c086015260e4840135908111610a545783019136602384011215610a54576004830135612eb08161382a565b93612ebe604051958661352e565b8185526024602086019260061b820101933685116106325750602401905b838210612efe57602061163488611629898960e0840152610104369101613878565b82604091612f0c3685613842565b815201910190612edc565b503461063257806003193601126106325760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461063257611071612f64366133e6565b916135d3565b50346106325780600319360112610632576020600754604051908152f35b503461063257602036600319011261063257600435808252600960205260ff600160408420015460a81c16156106a657612fc190613c48565b90600582101561140f5760208215838115612fe2575b506040519015158152f35b600191501482612fd7565b50346106325760203660031901126106325760043590818152600960205260ff600160408320015460a81c161561203357602091604082828152600985522060ff815460f01c168061307b575b613052575b50506001600160801b0360405191168152f35b61307492506001600160801b03600261306e9201541691613b65565b906135a4565b388061303f565b5060ff600182015460a01c161561303a565b5034610632576040366003190112610632576130a76133a6565b6024356130b381613b21565b33151580613173575b80613149575b6131195781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258680a48252600560205260408220906001600160a01b031982541617905580f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b038116845260066020526040842033855260205260ff604085205416156130c2565b50336001600160a01b03821614156130bc565b5034610632576020366003190112610632576020612266600435613580565b50346106325780600319360112610632576040519080600191600154928360011c9260018516948515613260575b6020958686108114611327578588528794939291879082156113055750506001146132065750506112979250038361352e565b90859250600182527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b85831061324857505061129793508201013880611289565b80548389018501528794508693909201918101613230565b93607f16936131d3565b5034610632578060031936011261063257602060405167016345785d8a00008152f35b905034610a54576020366003190112610a54576004357fffffffff0000000000000000000000000000000000000000000000000000000081168091036104a357602092507f80ac58cd000000000000000000000000000000000000000000000000000000008114908115613334575b811561330a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501438613303565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506132fc565b60005b8381106133715750506000910152565b8181015183820152602001613361565b9060209161339a8151809281855285808601910161335e565b601f01601f1916010190565b600435906001600160a01b038216820361062d57565b602435906001600160a01b038216820361062d57565b35906001600160a01b038216820361062d57565b606090600319011261062d576001600160a01b0390600435828116810361062d5791602435908116810361062d579060443590565b9181601f8401121561062d5782359167ffffffffffffffff831161062d576020808501948460051b01011161062d57565b90815180825260208080930193019160005b82811061346c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161345e565b3590811515820361062d57565b610120810190811067ffffffffffffffff821117611a3f57604052565b67ffffffffffffffff8111611a3f57604052565b6040810190811067ffffffffffffffff821117611a3f57604052565b610180810190811067ffffffffffffffff821117611a3f57604052565b6060810190811067ffffffffffffffff821117611a3f57604052565b90601f8019910116810190811067ffffffffffffffff821117611a3f57604052565b67ffffffffffffffff8111611a3f57601f01601f191660200190565b35906001600160801b038216820361062d57565b61358981613b21565b5060005260056020526001600160a01b036040600020541690565b6001600160801b0391821690821603919082116135bd57565b634e487b7160e01b600052601160045260246000fd5b906001600160a01b03809116801561380057600091848352602091600383526040928284862054161515806137f8575b806137e0575b6137c9578685526003815282848620541694873315159384613719575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79450876136e1575b808352600484528683206001815401905581835260038452868320816001600160a01b0319825416179055877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88519480a4878152a1831682036136b35750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61370282600052600560205260406000206001600160a01b03198154169055565b87835260048452868320805460001901905561364f565b91929380915090613788575b156137335790878392613626565b848887613750576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033861480156137ad575b806137255750878252600583523384868420541614613725565b5085825260068352848220338352835260ff8583205416613793565b602487855190630da9b01360e01b82526004820152fd5b506009815260ff6001858720015460b01c1615613609565b506001613603565b6024604051633250574960e11b815260006004820152fd5b359064ffffffffff8216820361062d57565b67ffffffffffffffff8111611a3f5760051b60200190565b919082604091031261062d5760405161385a816134d9565b602061387381839561386b8161356c565b855201613818565b910152565b919082604091031261062d57604051613890816134d9565b602080829461389e816133d2565b84520135910152565b91908110156138b75760051b0190565b634e487b7160e01b600052603260045260246000fd5b356001600160801b038116810361062d5790565b9081546138ed8161382a565b926040936138fe604051918261352e565b82815280946020809201926000526020600020906000935b85851061392557505050505050565b60018481928451613935816134d9565b64ffffffffff87546001600160801b038116835260801c1683820152815201930194019391613916565b9060405161396c81613512565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062d5790565b35801515810361062d5790565b91906139c18282856135d3565b803b6139ce575b50505050565b613a2a6001600160a01b03809216946040519384937f150b7a0200000000000000000000000000000000000000000000000000000000968786523360048701521660248501526044840152608060648401526084830190613381565b03906020816000938185885af190829082613ac0575b5050613a775782613a4f61463b565b8051919082613a705760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aa85750388080806139c8565b60249060405190633250574960e11b82526004820152fd5b909192506020813d602011613b19575b81613add6020938361352e565b81010312610a545751907fffffffff00000000000000000000000000000000000000000000000000000000821682036106325750903880613a40565b3d9150613ad0565b8060005260036020526001600160a01b03604060002054169081156129c3575090565b8051156138b75760200190565b80518210156138b75760209160051b010190565b64ffffffffff8042169180600052602090600a602052613b8860406000206138e1565b9084846020613b9685613b44565b5101511611613c3e57600052600960205260406000208484825460c81c161115613c2957506001600160801b039081613bce82613b44565b515116946001948594855b613be8575b5050505050505090565b8351871015613c2457828282613bfe8a88613b51565b5101511611613c24578585889981613c17849b89613b51565b5151160116980196613bd9565b613bde565b600201546001600160801b0316949350505050565b5050505050600090565b806000526009602052604060002060ff600182015460a01c16600014613c6f575050600490565b805460f81c613cc8575460a01c64ffffffffff164210613cc257613c9281613b65565b9060005260096020526001600160801b038060026040600020015416911610600014613cbd57600190565b600290565b50600090565b5050600390565b916000828152602090600382526001600160a01b03604095818784205416151580613e05575b80613ded575b613dd6579480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79596828552600386527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84838720541694859283613d9e575b169283613d88575b84875260038852808720846001600160a01b0319825416179055519580a4948152a1565b8387526004885280872060018154019055613d64565b613dbf86600052600560205260406000206001600160a01b03198154169055565b838852600489528488208054600019019055613d5c565b602486885190630da9b01360e01b82526004820152fd5b506009845260ff6001888520015460b01c1615613cfb565b508181161515613cf5565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e4257565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e8e6001600160801b0360408401511660206101008501510151906146ae565b6001600160801b0381511660e084015164ffffffffff60c086015116821561452a57801561450057815180156144d6577f000000000000000000000000000000000000000000000000000000000000000081116144a5575064ffffffffff6020613ef784613b44565b5101511681101561444e5750600090819082815184905b8082106143bd575050505064ffffffffff421664ffffffffff821681101561437d5750506001600160801b0316808203614346575050600754928360005260096020526040600020916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140aa8951996000198b0190613b51565b51015160c81b169560f01b16911617171717845560005b8181106142a1575050600185016007556001600160a01b036020830151168015613800576140f7866001600160a01b0392613ccf565b16614270576141226001600160a01b036060840151166001600160801b038351169030903390614787565b6001600160801b0360208201511680614240575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661423561421660808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141bf8c6134d9565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061344c565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b61426a906001600160a01b036060850151166001600160a01b036101008601515116903390614787565b38614136565b60246040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152fd5b86600052600a6020526040600020906142be8160e0870151613b51565b51825468010000000000000000811015611a3f57600181018085558110156138b757600193600052602060002001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140c1565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143e1906001600160801b036143d88588613b51565b51511690614693565b9364ffffffffff8060206143f58685613b51565b5101511694168085111561441157506001849301909291613f0e565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061445f84613b44565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b60009080825260036020526001600160a01b038060408420541692833314938415614599575b5050821561458757505090565b9091506145943392613580565b161490565b60ff929450906040918152600660205281812033825260205220541691388061457a565b8060005260096020526145d6600260406000200161395f565b816000526009602052604060002060ff600182015460a01c1660001461460957506001600160801b039150602001511690565b5460f81c61461e575061461b90613b65565b90565b61461b91506001600160801b0360408183511692015116906135a4565b3d15614666573d9061464c82613550565b9161465a604051938461352e565b82523d6000602084013e565b606090565b61461b90614678816145bd565b90600052600960205260026040600020015460801c906135a4565b9190916001600160801b03808094169116019182116135bd57565b919091604051906146be826134d9565b600091828152826020820152936001600160801b03928383169182156147685767016345785d8a000080821161473157506146fa8591846148e9565b166020870192818452111561471d57509082614718925116906135a4565b168252565b80634e487b7160e01b602492526001600452fd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b509394505050506040519061477c826134d9565b808252602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a3f576147f69260405261484d565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147f69161484d60648361352e565b6001600160a01b031690614878600080836020829551910182875af161487161463b565b9084614998565b9081519182151592836148c1575b5050506148905750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819293509060209181010312610a545760200151908115918215036106325750388080614886565b9091906000198382098382029182808310920391808303921461498757670de0b6b3a7640000908183101561495057947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149d757508051156149ad57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614a22575b6149e8575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149e056fea164736f6c6343000817000a"; + hex"60c034620003c3576001600160401b0390601f601f1962004de93881900383810183168501919086831186841017620002e557808692606094604052833981010312620003c35782516001600160a01b038082169590929091869003620003c35760209485810151938416809403620003c357604001519362000081620003c7565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003c7565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002e5576001988954908a82811c92168015620003b8575b84831014620002c657818684931162000365575b50839086831160011462000305575f92620002f9575b50505f19600383901b1c191690891b1788555b8151948511620002e557600254938885811c95168015620002da575b82861014620002c65784848796116200026c575b5081938511600114620002065750505f92620001fa575b50505f19600383901b1c191690841b176002555b60018060a01b031984815f5416175f556008541617600855604051925f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a019081620003e8823960805181613e09015260a051818181612f120152613eaf0152f35b015190505f8062000179565b8895939291931660025f52835f20935f905b82821062000252575050841162000239575b505050811b016002556200018d565b01515f1960f88460031b161c191690555f80806200022a565b8484015186558a9790950194938401939081019062000218565b90919293945060025f52825f208580880160051c820192858910620002bc575b9188978c9297969594930160051c01915b828110620002ad57505062000162565b5f81558897508b91016200029d565b925081926200028c565b634e487b7160e01b5f52602260045260245ffd5b94607f16946200014e565b634e487b7160e01b5f52604160045260245ffd5b015190505f806200011f565b90878c941691845f52855f20925f5b878282106200034e575050841162000335575b505050811b01885562000132565b01515f1960f88460031b161c191690555f808062000327565b8385015186558f9790950194938401930162000314565b9091508a5f52835f208680850160051c820192868610620003ae575b918d91869594930160051c01915b8281106200039f57505062000109565b5f81558594508d91016200038f565b9250819262000381565b91607f1691620000f5565b5f80fd5b60408051919082016001600160401b03811183821017620002e55760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a7146132b257508063027b67441461329057806306fdde031461319a578063081812fc1461317c578063095ea7b3146130835780631400ecec14612fe35780631c1cdd4c14612f6b5780631e99d56914612f4e57806323b872dd14612f355780632fe4304114612efb57806332fbe22b14612da657806340e58ee514612aea578063425d30dd14612a9957806342842e0e14612a5f57806342966c6814612896578063442675701461286f5780634857501f146127f95780634869e12d146127be5780634cc55e11146122fb57806357404b12146122645780636352211e146122345780636d0cee751461223457806370a08231146121c457806375829def146121315780637cad6cd1146120385780637de6b1db14611e135780637f5799f914611db85780638659c27014611a5f578063894e9a0d146116d5578063897f362b146114285780638f69b9931461138d5780639067b6771461133d57806395d89b411461122e578063a22cb46514611173578063a80fc07114611121578063ad35efd4146110bf578063b25645691461106e578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5d578063bc2be1be14610f0d578063c156a11d14610a5e578063c87b56dd14610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610805578063ea5ead191461070b578063eac8f5b8146106b9578063f590c17614610657578063f851a440146106315763fdd46d601461025a575f80fd5b3461062e57606036600319011261062e57600435906102776133dd565b91604435926001600160801b038085169182860361062a57610297613dff565b83855260099560209387855260ff600160408920015460a81c16156106135785875287855260ff600160408920015460a01c166105fb576001600160a01b039081841680156105e35781156105cb57878952600387528260408a2054169283821415806105bb575b6105975761030c89614646565b8781168411610565575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c906103409161466c565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561037690613968565b90808483015116918180825116916040015116610392916135c2565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610536575b848c528252600160408c20015416946103d7818a886147ca565b604051908152a4803314158061052c575b6104be575b8333141590816104b3575b816104a8575b50610432575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a457604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048c575b8080610404565b610495906134e5565b6104a057825f610485565b8280fd5b8380fd5b90508314155f6103fe565b843b151591506103f8565b803b1561052857604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610514575b50506103ed565b61051d906134e5565b61052857845f61050d565b8480fd5b50803b15156103e8565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103bd565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c589614539565b156102ff565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b5f80fd5b80fd5b503461062e578060031936011261062e576001600160a01b036020915416604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760016040836001600160a01b0393602095526009855220015416604051908152f35b503461062e57604036600319011261062e57600435906107296133dd565b9161073381614646565b9261073c613dff565b81835260099360209185835260ff600160408720015460a81c16156107ee5783855285835260ff600160408720015460a01c166107d6576001600160a01b03918282169283156107be576001600160801b03938483169081156105cb57878952600387528260408a2054169283821415806105bb576105975761030c89614646565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b503461062e57604036600319011261062e5761081f6133c7565b60406108296133dd565b926001600160a01b03809316815260066020522091165f52602052602060ff60405f2054166040519015158152f35b503461062e57602036600319011261062e5760ff6001604060043593848152600960205220015460a81c16156106a257610893602091614646565b6001600160801b0360405191168152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257604082600292602094526009845220015460801c604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760036040836001600160801b0393602095526009855220015416604051908152f35b503461062e57602080600319360112610a4e5760043561096181613b24565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a525780936109d1575b50506109cd6040519282849384528301906133a2565b0390f35b909192503d8082843e6109e4818461354e565b8201918381840312610a4e5780519067ffffffffffffffff82116104a0570182601f82011215610a4e57805191610a1a83613570565b93610a28604051958661354e565b83855285848401011161062e575090610a4691848085019101613381565b905f806109b7565b5080fd5b604051903d90823e3d90fd5b503461062e57604036600319011261062e57600435610a7b6133dd565b610a83613dff565b81835260099060209082825260ff600160408720015460a81c16156107ee57838552600382526001600160a01b03918260408720541693843303610eee57610aca86614646565b906001600160801b039081831680158015610b6a575b50505050505081811615610b525783610af891613cc4565b90811680610b185760248460405190637e27328960e01b82526004820152fd5b8203610b22578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b72613dff565b898b5282865260ff600160408d20015460a81c1615610ed757898b5282865260ff600160408d20015460a01c16610ebf578815610ea757610e8f57888a52600385528660408b205416918289141580610e7f575b610e5b57610bd38a614646565b8481168311610e295750908a949392918a86528087526040862093610c38610c068760028d89541698015460801c61466c565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155613968565b90610c54818a84015116928260408183511692015116906135c2565b161115610dfa575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610c9b8186886147ca565b604051908152a48033141580610df0575b610d86575b813314159081610d7b575b81610d70575b50610cff575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a15f8080808080610ae0565b803b156104a057604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d58575b80610cc8565b610d61906134e5565b610d6c57855f610d52565b8580fd5b90508114155f610cc2565b823b15159150610cbc565b803b156104a457604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610ddc575b5050610cb1565b610de5906134e5565b6104a457835f610dd5565b50803b1515610cac565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c5c565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610e898a614539565b15610bc6565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576040826001600160a01b03926020945260098452205416604051908152f35b503461062e57602036600319011261062e5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461062e57608036600319011261062e57610ffb6133c7565b6110036133dd565b906064359067ffffffffffffffff82116104a457366023830112156104a4578160040135928461103285613570565b93611040604051958661354e565b8585523660248783010111610a4e578561106b966024602093018388013785010152604435916139bd565b80f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257600160408360ff93602095526009855220015460b01c166040519015158152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576110f890613c44565b60405190600581101561110d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760026040836001600160801b0393602095526009855220015416604051908152f35b503461062e57604036600319011261062e5761118d6133c7565b6024359081151580920361062a576001600160a01b03169081156111fd57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e578060031936011261062e5760405190806002549160018360011c9260018516948515611333575b602095868610811461131f578588528794939291879082156112fd5750506001146112a3575b505061128f9250038361354e565b6109cd6040519282849384528301906133a2565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106112e557505061128f93508201015f80611281565b805483890185015287945086939092019181016112cd565b925093505061128f94915060ff191682840152151560051b8201015f80611281565b602483634e487b7160e01b81526022600452fd5b93607f169361125b565b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576113c690613c44565b9060058210159081611407576002831491821561141b575b82156113f2575b6020836040519015158152f35b90915061140757506004602091145f806113e5565b80634e487b7160e01b602492526021600452fd5b506003831491505f6113de565b503461062e576020906003198281360112610a4e576004359167ffffffffffffffff91828411610a4e5761012084360391820112610a4e57611468613dff565b60c48401359060221901811215610a4e5783016004810135928311610a4e5760248101908360061b80360383136104a4576024906114a586613838565b956114b3604051978861354e565b8652878601920101913683116104a457905b868383106116bd57505050508151906114dd82613838565b926114eb604051948561354e565b828452601f196114fa84613838565b0186835b82811061169b5750505064ffffffffff804216936001600160801b03928361152582613b45565b51511683808b61153485613b45565b5101511688011660405191611548836134f9565b82528a82015261155788613b45565b5261156187613b45565b5060019260015b8381106116335750505050506115808560040161399c565b9161158d6024870161399c565b9161159a604488016138d9565b6064880135926001600160a01b039081851680950361062e5750928895926115eb98959261162098956115d2608461162b9d016139b0565b94816115e060a48c016139b0565b976040519d8e6134c8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613886565b610100820152613e5b565b604051908152f35b8089838d8180826116578d6116498e9a8d613b52565b515116965f19890190613b52565b5101511691611666868a613b52565b51015116011660405191611679836134f9565b82528d820152611689828c613b52565b52611694818b613b52565b5001611568565b6040516116a7816134f9565b5f81525f838201528282890101520187906114fe565b6040916116ca3685613850565b8152019101906114c5565b503461062e57602036600319011261062e5760606101606040516116f881613515565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201528361012082015260405161173e81613532565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611a475760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a335761182f9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613968565b610120830152611840600435613c44565b6005811015611a1f57610160926118eb9260026119279314611a14575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613515565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138ed565b828201526109cd604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061346d565b80606083015261185d565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b5f52604160045260245ffd5b602460405162b8e7e760e51b81526004356004820152fd5b503461062e57602080600319360112610a4e5760043567ffffffffffffffff81116104a057611a9290369060040161343c565b9190611a9c613dff565b83925b808410611aaa578480f35b611ab58482846138b5565b3593611abf613dff565b848652600980855260ff600191818360408b20015460a81c1615611da157878952808752604089208381015460a01c831615611b0d5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d8957611b3c815f5260096020526001600160a01b0360405f205416331490565b15611d6957611b4a81613b66565b93818a52828952611b60600260408c2001613968565b946001600160801b0394858751168683161015611d5157838c52848b5260408c205460f01c1615611d3957918493918a611bac85878f9a99808c9986928d511603169a015116906135c2565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611c8560408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611d20575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611c5d8b85886147ca565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611cc9575b505050505050600101929190611a9f565b813b15610d6c57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d0c575b80808080611cb8565b611d15906134e5565b61052857845f611d03565b818601600160a01b60ff60a01b19825416179055611c13565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257604082611dff926109cd9452600a602052206138ed565b60405191829160208352602083019061346d565b503461062e57602080600319360112610a4e5760043590611e32613dff565b8183526009815260ff600160408520015460a81c161561202157611e5582613c44565b600581101561200d5760048103611e7e5760248360405190634a5541ef60e01b82526004820152fd5b60038103611e9e576024836040519063fe19f19f60e01b82526004820152fd5b600214611ff557611ec3825f5260096020526001600160a01b0360405f205416331490565b15611fd6578183526009815260ff604084205460f01c1615611fbe57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611f66575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a057816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611faa575b80611f37565b611fb3906134e5565b6104a057825f611fa4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e576004356001600160a01b03908181168091036104a05781835416338103612108575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120f45760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461062e57602036600319011261062e5761214b6133c7565b9080546001600160a01b038082169333850361219d576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461062e57602036600319011261062e576001600160a01b036121e66133c7565b168015612203578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e57602036600319011261062e576020612253600435613b24565b6001600160a01b0360405191168152f35b503461062e57602036600319011261062e576004355f6020604051612288816134f9565b8281520152808252600960205260ff600160408420015460a81c16156106a257604082819281526009602052205464ffffffffff8251916122c8836134f9565b818160a01c16835260c81c1660208201526122f9825180926020908164ffffffffff91828151168552015116910152565bf35b503461062e57604036600319011261062e5767ffffffffffffffff6004358181116104a05761232e90369060040161343c565b909160249081359081116105285761234a90369060040161343c565b612355929192613dff565b80840361278857855b848110612369578680f35b6123748186886138b5565b35906123818187896138b5565b35885260036020526001600160a01b036040892054166123aa6123a58386896138b5565b6138d9565b906123b3613dff565b838a52600960205260ff600160408c20015460a81c161561277257838a52600960205260ff600160408c20015460a01c1661275b578015612744576001600160801b0382161561272d57838a5260036020526001600160a01b0360408b20541691828214158061271d575b6126f95761242b85614646565b6001600160801b0381166001600160801b038316116126c95750908a9291858452600960205260408420926124b16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961249387608094851c61466c565b938c8b52600960205260408b2001938454931b169116178155613968565b6001600160801b036124d581602084015116928260408183511692015116906135c2565b161115612698575b86855260096020526001600160a01b0360016040872001541661250a6001600160801b03841685836147ca565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061268e575b612624575b833314159081612619575b8161260e575b5061259c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161235e565b823b156104a457604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125f6575b8080612565565b6125ff906134e5565b61260a57875f6125ef565b8780fd5b90508314155f61255f565b843b15159150612559565b803b1561052857604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161267a575b505061254e565b612683906134e5565b61052857845f612673565b50803b1515612549565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124dd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061272785614539565b1561241e565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b503461062e57602036600319011261062e5760ff6001604060043593848152600960205220015460a81c16156106a25761089360209161459e565b503461062e57602036600319011261062e5760043590818152600960205260ff600160408320015460a81c1615612021578061283483613c44565b926005841015611a1f57600260209403612855575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80612849565b503461062e578060031936011261062e5760206001600160a01b0360085416604051908152f35b503461062e57602080600319360112610a4e57600435906128b5613dff565b8183526009815260ff600160408520015460a81c1615612021578183526009815260ff600160408520015460a01c1615612a2e576128f282614539565b15611fd657815f52600381526001600160a01b038060405f205416151580612a27575b80612a0e575b6129f6577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f2054169182159283156129c0575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129a8575080f35b60249060405190637e27328960e01b82526004820152fd5b6129df855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f198154019055612959565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c161561291b565b505f612915565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e57612a6e36613407565b60405191602083019383851067ffffffffffffffff861117611a335761106b946040528584526139bd565b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257600160408360ff93602095526009855220015460a01c166040519015158152f35b503461062a5760208060031936011261062a5760043590612b09613dff565b815f52600980825260ff600160405f20015460a81c1615612d8f57825f5280825260405f2060ff600182015460a01c165f14612b575760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612d7757612b7d835f5260096020526001600160a01b0360405f205416331490565b15612d5857612b8b83613b66565b835f52818352612ba0600260405f2001613968565b936001600160801b0391828651168382161015611ff557815f5283855260ff60405f205460f01c1615611fbe57612c06818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906135c2565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88161789558216978815612d3e575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f2001541693612cb78c84876147ca565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b612ceb578580f35b813b1561062a575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d2d575b808080808580f35b612d3791506134e5565b5f80612d25565b60018101600160a01b60ff60a01b19825416179055612c4a565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461062a576003196020368201811361062a576004359067ffffffffffffffff9283831161062a5761014090833603011261062a57612de3613dff565b60405192612df0846134c8565b612dfc836004016133f3565b8452612e0a602484016133f3565b6020850152612e1b6044840161358c565b604085015260648301356001600160a01b038116810361062a576060850152612e46608484016134bb565b6080850152612e5760a484016134bb565b60a0850152612e6860c48401613826565b60c085015260e483013590811161062a5782013660238201121561062a57600481013591612e9583613838565b92612ea3604051948561354e565b8084526024602085019160061b8401019236841161062a57602401905b838210612ee257602061162b88611620898960e0840152610104369101613886565b82604091612ef03685613850565b815201910190612ec0565b3461062a575f36600319011261062a5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461062a57612f4c612f4636613407565b916135ef565b005b3461062a575f36600319011261062a576020600754604051908152f35b3461062a57602036600319011261062a57600435805f52600960205260ff600160405f20015460a81c16156106a257612fa390613c44565b6005811015612fcf578060209115908115612fc4575b506040519015158152f35b600191501482612fb9565b634e487b7160e01b5f52602160045260245ffd5b3461062a57602036600319011261062a57600435805f52600960205260ff600160405f20015460a81c16156106a2576020905f90805f526009835260405f2060ff815460f01c1680613071575b613048575b50506001600160801b0360405191168152f35b61306a92506001600160801b0360026130649201541691613b66565b906135c2565b8280613035565b5060ff600182015460a01c1615613030565b3461062a57604036600319011261062a5761309c6133c7565b6024356130a881613b24565b33151580613169575b8061313f575b61310f5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f205416156130b7565b50336001600160a01b03821614156130b1565b3461062a57602036600319011261062a5760206122536004356135a0565b3461062a575f36600319011261062a576040515f600190600154918260011c9160018416918215613286575b60209485851084146132725785879486865291825f146132525750506001146131f7575b5061128f9250038361354e565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b85831061323a57505061128f9350820101856131ea565b80548389018501528794508693909201918101613223565b60ff19168582015261128f95151560051b85010192508791506131ea9050565b634e487b7160e01b5f52602260045260245ffd5b92607f16926131c6565b3461062a575f36600319011261062a57602060405167016345785d8a00008152f35b3461062a57602036600319011261062a57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361062a57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115613357575b811561332d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613326565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061331f565b5f5b8381106133925750505f910152565b8181015183820152602001613383565b906020916133bb81518092818552858086019101613381565b601f01601f1916010190565b600435906001600160a01b038216820361062a57565b602435906001600160a01b038216820361062a57565b35906001600160a01b038216820361062a57565b606090600319011261062a576001600160a01b0390600435828116810361062a5791602435908116810361062a579060443590565b9181601f8401121561062a5782359167ffffffffffffffff831161062a576020808501948460051b01011161062a57565b9081518082526020808093019301915f5b82811061348c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161347e565b3590811515820361062a57565b610120810190811067ffffffffffffffff821117611a3357604052565b67ffffffffffffffff8111611a3357604052565b6040810190811067ffffffffffffffff821117611a3357604052565b610180810190811067ffffffffffffffff821117611a3357604052565b6060810190811067ffffffffffffffff821117611a3357604052565b90601f8019910116810190811067ffffffffffffffff821117611a3357604052565b67ffffffffffffffff8111611a3357601f01601f191660200190565b35906001600160801b038216820361062a57565b6135a981613b24565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b0391821690821603919082116135db57565b634e487b7160e01b5f52601160045260245ffd5b906001600160a01b0380911690811561380f57835f526020906003825260409181835f205416151580613807575b806137ef575b6137d857855f526003815281835f2054169333151580613731575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856136fc575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036136ce5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61371b885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f198154019055613668565b80613797575b15613742575f61363e565b83878661375f576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033851480156137bc575b806137375750865f52600582523383855f20541614613737565b50845f5260068252835f20335f52825260ff845f2054166137a2565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c1615613623565b50600161361d565b6024604051633250574960e11b81525f6004820152fd5b359064ffffffffff8216820361062a57565b67ffffffffffffffff8111611a335760051b60200190565b919082604091031261062a57604051613868816134f9565b60206138818183956138798161358c565b855201613826565b910152565b919082604091031261062a5760405161389e816134f9565b60208082946138ac816133f3565b84520135910152565b91908110156138c55760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361062a5790565b9081546138f981613838565b9260409361390a604051918261354e565b82815280946020809201925f5260205f20905f935b85851061392e57505050505050565b6001848192845161393e816134f9565b64ffffffffff87546001600160801b038116835260801c168382015281520193019401939161391f565b9060405161397581613532565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062a5790565b35801515810361062a5790565b919290926139cc8185856135ef565b833b6139d9575b50505050565b6020906001600160a01b0380951694613a3a60405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906133a2565b03815f875af15f9181613ac7575b50613a7e5782613a56614617565b8051919082613a775760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aaf57505f8080806139d3565b60249060405190633250574960e11b82526004820152fd5b9091506020813d602011613b1c575b81613ae36020938361354e565b8101031261062a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361062a57905f613a48565b3d9150613ad6565b805f5260036020526001600160a01b0360405f2054169081156129a8575090565b8051156138c55760200190565b80518210156138c55760209160051b010190565b64ffffffffff80421691805f52602090600a602052613b8760405f206138ed565b9084846020613b9585613b45565b5101511611613c3b575f52600960205260405f208484825460c81c161115613c2657506001600160801b039081613bcb82613b45565b515116946001948594855b613be5575b5050505050505090565b8351871015613c2157828282613bfb8a88613b52565b5101511611613c21578585889981613c14849b89613b52565b5151160116980196613bd6565b613bdb565b600201546001600160801b0316949350505050565b50505050505f90565b805f52600960205260405f2060ff600182015460a01c165f14613c68575050600490565b805460f81c613cbd575460a01c64ffffffffff164210613cb857613c8b81613b66565b905f5260096020526001600160801b0380600260405f200154169116105f14613cb357600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f205416151580613df4575b80613ddc575b613dc5578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f2054169283613d90575b169283613d7a575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f2060018154019055613d33565b613daf835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613d2b565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613cee565b508581161515613ce8565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e3157565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e7d6001600160801b036040840151166020610100850151015190614687565b6001600160801b0381511660e084015164ffffffffff60c086015116821561450f5780156144e557815180156144bb577f0000000000000000000000000000000000000000000000000000000000000000811161448a575064ffffffffff6020613ee684613b45565b5101511681101561443357505f905f905f81515f905b8082106143a2575050505064ffffffffff421664ffffffffff82168110156143625750506001600160801b031680820361432b57505060075492835f52600960205260405f20916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140958951995f198b0190613b52565b51015160c81b169560f01b1691161717171784555f5b81811061428a575050600185016007556001600160a01b03602083015116801561380f576140e1866001600160a01b0392613cc4565b1661425a5761410c6001600160a01b036060840151166001600160801b038351169030903390614759565b6001600160801b036020820151168061422a575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661421f61420060808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a98c6134f9565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061346d565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b614254906001600160a01b036060850151166001600160a01b036101008601515116903390614759565b5f614120565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b865f52600a60205260405f20906142a58160e0870151613b52565b51825468010000000000000000811015611a3357600181018085558110156138c5576001935f5260205f2001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140ab565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143c6906001600160801b036143bd8588613b52565b5151169061466c565b9364ffffffffff8060206143da8685613b52565b510151169416808511156143f657506001849301909291613efc565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061444484613b45565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f2054169182331492831561457b575b50821561456957505090565b90915061457633926135a0565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f61455d565b805f5260096020526145b5600260405f2001613968565b815f52600960205260405f2060ff600182015460a01c165f146145e557506001600160801b039150602001511690565b5460f81c6145fa57506145f790613b66565b90565b6145f791506001600160801b0360408183511692015116906135c2565b3d15614641573d9061462882613570565b91614636604051938461354e565b82523d5f602084013e565b606090565b6145f7906146538161459e565b905f526009602052600260405f20015460801c906135c2565b9190916001600160801b03808094169116019182116135db57565b919091604051614696816134f9565b5f81525f6020820152926001600160801b039182811691821561473b5767016345785d8a000080821161470457506146cf8491846148b3565b16602086019281845211156146f057826146eb925116906135c2565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050905060405161474d816134f9565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a33576147c89260405261481f565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147c89161481f60648361354e565b5f806001600160a01b0361484893169360208151910182865af1614841614617565b9083614961565b805190811515918261488f575b505061485e5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261062a576020015180159081150361062a575f80614855565b9091905f198382098382029182808310920391808303921461495057670de0b6b3a7640000908183101561491957947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149a0575080511561497657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149eb575b6149b1575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149a956fea164736f6c6343000817000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"6080806040523461001757615f5890816200001d8239f35b600080fdfe600436101561000d57600080fd5b60003560e01c63e9dc63751461002257600080fd5b3461442a57604036600319011261442a576001600160a01b03600435166004350361442a5761022060405260006080819052606060a081905260c082905260e08290526101008190526101208190526101608190526101808190526101a08190526101c0526101e0819052610200526004356001600160a01b038116610140526100ab90614b3b565b610160526100c36004356001600160a01b0316614d53565b61018052610140516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561443757600091614909575b506001600160a01b03610134911680608052614e74565b60a052610140516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576fffffffffffffffffffffffffffffffff916000916148ea575b501660c052610140516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa8015614437576000906148ad575b6102029150614fc1565b6101a052610140516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156144375760009161487e575b5060c0516fffffffffffffffffffffffffffffffff168015614868576fffffffffffffffffffffffffffffffff6127108193021604166101606080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102d38161499a565b51902061041360296102f563ffffffff61016861ffff8660101c160616615736565b61032363ffffffff601e604660ff6103198460146050848d60081c16060116615736565b9816060116615736565b6040519485927f68736c28000000000000000000000000000000000000000000000000000000006020850152610363815180926020602488019101614952565b83017f2c00000000000000000000000000000000000000000000000000000000000000602482015261039f825180936020602585019101614952565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103dd8351809460206027868601019101614952565b01017f25290000000000000000000000000000000000000000000000000000000000006027820152036009810184520182614a26565b61044b6fffffffffffffffffffffffffffffffff6040608001511660ff6104446001600160a01b03608051166150bd565b1690615226565b61045f6001600160a01b0360805116614d53565b90602060800151602460206001600160a01b0360c06080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa801561443757602491600091614849575b5060206001600160a01b0360c06080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa8015614437576105259260009161481a575b5064ffffffffff8091169116615571565b610180516101e0519092916105af602161054c6064610545818706615a4f565b9504615736565b6040519481610565879351809260208087019101614952565b820161057a8251809360208085019101614952565b017f25000000000000000000000000000000000000000000000000000000000000006020820152036001810185520183614a26565b6101606080015192610120608001519660e06080015196604051998a61014081011067ffffffffffffffff6101408d01111761444b576101408b016040528a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405260608152600060208201526000604082015260608082015260006080820152606060a0820152600060c0820152600060e08201526060610100820152600061012082015260006101408201526060610160820152600061018082015260006101a082015260a08201516106bd60c0840151845190615b5b565b906109a461015c604051926106d184614a0a565b600884527f50726f6772657373000000000000000000000000000000000000000000000000602085015261071460405161070a816149b6565b6000815286615a12565b15614812576090945b61072686615736565b916040519586938493661e339034b21e9160c91b60208601526109728351958692610758846027840160208901614952565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b6035858401015261079f8551809660206042888701019101614952565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e88201528651966108a591889160f990910190602001614952565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761094091899161015190910190602001614952565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614952565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c81019091520182614a26565b6101008301526101208201526028610120830151604051906109c5826149b6565b60008252610c6b61015c604051926109dc84614a0a565b600684527f53746174757300000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b610a1882615ed5565b8082111561480a5750945b610a2e878701615736565b91604051958693661e339034b21e9160c91b60208601528151610a58816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a9b825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b9782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c2682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610c4d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810184520182614a26565b610160840152016101808201526028602083015160405190610c8c826149b6565b60008252610cd661015c60405192610ca384614a0a565b600684527f416d6f756e7400000000000000000000000000000000000000000000000000006020850152610a0f84615e57565b835201602082015261101160808301516030604051610cf4816149b6565b60008152610f9b61015c60405194610d0b86614a0a565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d3e86615e57565b610d4782615ed5565b808211156148025750935b610d5e60288601615736565b91604051978893661e339034b21e9160c91b60208601528151610d88816027880160208601614952565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610dcb825180936020604285019101614952565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610ec782518093602060f985019101614952565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f5682518093602061015185019101614952565b01661e17ba32bc3a1f60c91b610151820152610f7d82518093602061015885019101614952565b01631e17b39f60e11b6101588201520361013c810186520184614a26565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e08401526101008301516101608401518451916151bc565b6060820152604051908161010081011067ffffffffffffffff6101008401111761444b57610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161012084015191606081015194604051611167816149d2565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051968761014081011067ffffffffffffffff6101408a01111761444b57610140880160405261011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b01111761444b576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761444b57611cbc611d1d9160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c0152611873615b22565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d1860d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d2200009384604085015280516119a560b88660208501936118e581605e840187614952565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b607382015261194a825180936020609385019101614952565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a7820152036098810188520186614a26565b6119ad615b22565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d8801528251611a1381606b8a0184614952565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a58825180936020608e85019101614952565b019082608e830152611a9c60a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b520189614a26565b611be2610108611aaa615b22565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b36815180926020607387019101614952565b8201908760738301526076820152875190611b55826096830188614952565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a614a26565b611bea615b22565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614952565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611cfe82518093602060c485019101614952565b019160c483015260c78201520360b8810187520185614a26565b6151bc565b92611d2f611d29614f4f565b89615a12565b9788156147e7575b50604051611d44816149ee565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c08701111761444b576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152896000146145c257604051612172816149b6565b60008152995b1561446157604051806101e081011067ffffffffffffffff6101e08301111761444b576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761444b57613b859c612e406036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612f119f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612ddc8151809260208a8c019101614952565b8701612df18251809360208a85019101614952565b01612e058251809360208985019101614952565b01612e198251809360208885019101614952565b01612e2d8251809360208785019101614952565b0191820152036016810186520184614a26565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e856026998260208c9451948593019101614952565b8901612e9a8251809360208c85019101614952565b01612eae8251809360208b85019101614952565b01612ec28251809360208a85019101614952565b01612ed68251809360208985019101614952565b01612eea8251809360208885019101614952565b01612efe8251809360208785019101614952565b019182015203600d810189520187614a26565b6137a4604c60e0830151610100840151936135006131336060604084015193015196612f3d8186615d9b565b9461312e61012b604051612f5081614a0a565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fba815180926020603787019101614952565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130fe91849161012090910190602001614952565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b81019091520187614a26565b615d9b565b9561331261012b60405161314681614a0a565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d2200000000000000000060208401526131b0815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132ed82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a520188614a26565b61331c8184615e03565b926134fb61012b60405161332f81614a0a565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613399815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134d682518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810187520185614a26565b615e03565b906136df61012b60405161351381614a0a565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d22000000000000000000602084015261357d815180926020603787019101614952565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136ba82518093602061012085019101614952565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810185520183614a26565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e0000000000000000000000000000000000000000000000000000006040860152613745815180926020604589019101614952565b840161375b825180936020604585019101614952565b01613770825180936020604585019101614952565b01613785825180936020604585019101614952565b01661e17ba32bc3a1f60c91b604582015203602c810184520182614a26565b613a8461019a6101408401516101a0850151906137e56137df6137d96137d360e060408b01519a015194615736565b94615736565b97615736565b91615736565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e86015261012790613980815180926020858a019101614952565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139ea8251809360208b85019101614952565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a2d8251809360208985019101614952565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a708251809360208785019101614952565b01918201520361017a810185520183614a26565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613b10815180926020607b89019101614952565b8401613b26825180936020607b85019101614952565b01613b3b825180936020607b85019101614952565b01613b50825180936020607b85019101614952565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b820152036061810184520182614a26565b610140608001526000806001600160a01b0360c0608001511660405160208101907fb2564569000000000000000000000000000000000000000000000000000000008252602435602482015260248152613bde816149d2565b51915afa613bea614aa9565b61012081905290158015610200526144435760208180518101031261442a5760200151801515810361442a575b151560e05260a051610140516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa908115614437576000916143ec575b506141fd6142ee609461436094613db66089613c936142f997614d53565b92610120608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613cdb815180926020604088019101614952565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613d40825180936020606385019101614952565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d81825180936020608685019101614952565b017f227d5d00000000000000000000000000000000000000000000000000000000006086820152036069810184520182614a26565b6101605160a0516101805160805190926140e79160e39190613de0906001600160a01b0316614d53565b94613dec602435615736565b60e0519096901561436457604051613e03816149ee565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461408360208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613f338160558c0184614952565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613fbd8260b183018a614952565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613ff882518093602060c385019101614952565b016140317f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614952565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c782015261406f82518093602060d185019101614952565b019260d184015251809360d5840190614952565b019060d582015261409e82518093602060df85019101614952565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140d88251809360208785019101614952565b010360c3810185520183614a26565b61016051906142586140fa602435615736565b91614179602d604051809560208201976a029b0b13634b2b9102b19160ad1b895261412f815180926020602b87019101614952565b82017f2023000000000000000000000000000000000000000000000000000000000000602b82015261416a8251809360208785019101614952565b0103600d810186520184614a26565b6101c05161418690615887565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a01526141c7815180926020602e8d019101614952565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614952565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614952565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d8201526142b9825180936020609285019101614952565b017f227d0000000000000000000000000000000000000000000000000000000000006092820152036074810184520182614a26565b610100819052615887565b61434c603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000602083015261433c8151809260208686019101614952565b810103601d810184520182614a26565b604051918291602083526020830190614975565b0390f35b6040516143708161499a565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613ec7565b90506020813d60201161442f575b8161440760209383614a26565b8101031261442a5751906001600160a01b038216820361442a57906141fd613c75565b600080fd5b3d91506143fa565b6040513d6000823e3d90fd5b506001613c17565b634e487b7160e01b600052604160045260246000fd5b6040518061012081011067ffffffffffffffff6101208301111761444b57610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123c5565b604051806101c081011067ffffffffffffffff6101c08301111761444b576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015299612178565b6147fb9198506147f5614f88565b90615a12565b9638611d37565b905093610d52565b905094610a23565b60d09461071d565b61483c915060203d602011614842575b6148348183614a26565b810190614a70565b38610514565b503d61482a565b614862915060203d602011614842576148348183614a26565b386104bd565b634e487b7160e01b600052601260045260246000fd5b6148a0915060203d6020116148a6575b6148988183614a26565b810190614a48565b3861025c565b503d61488e565b506020813d6020116148e2575b816148c760209383614a26565b8101031261442a5751600581101561442a57610202906101f8565b3d91506148ba565b614903915060203d6020116148a6576148988183614a26565b3861019e565b90506020813d60201161494a575b8161492460209383614a26565b8101031261442a57516001600160a01b038116810361442a576001600160a01b0361011d565b3d9150614917565b60005b8381106149655750506000910152565b8181015183820152602001614955565b9060209161498e81518092818552858086019101614952565b601f01601f1916010190565b6080810190811067ffffffffffffffff82111761444b57604052565b6020810190811067ffffffffffffffff82111761444b57604052565b6060810190811067ffffffffffffffff82111761444b57604052565b60c0810190811067ffffffffffffffff82111761444b57604052565b6040810190811067ffffffffffffffff82111761444b57604052565b90601f8019910116810190811067ffffffffffffffff82111761444b57604052565b9081602091031261442a57516fffffffffffffffffffffffffffffffff8116810361442a5790565b9081602091031261442a575164ffffffffff8116810361442a5790565b67ffffffffffffffff811161444b57601f01601f191660200190565b3d15614ad4573d90614aba82614a8d565b91614ac86040519384614a26565b82523d6000602084013e565b606090565b60208183031261442a5780519067ffffffffffffffff821161442a570181601f8201121561442a578051614b0c81614a8d565b92614b1a6040519485614a26565b8184526020828401011161442a57614b389160208085019101614952565b90565b6001600160a01b031660408051916395d89b4160e01b8352600083600481845afa928315614d4857600093614d25575b50815192614b7884614a0a565b60118452614bad6020947f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000008682015282615a12565b15614beb5750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614be183614a0a565b600d835282015290565b614c288351614bf981614a0a565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000008682015282615a12565b15614c665750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c5c83614a0a565b600e835282015290565b614ca38351614c7481614a0a565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000008682015282615a12565b15614ce15750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614cd783614a0a565b600f835282015290565b614d219083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614975565b0390fd5b614d4191933d8091833e614d398183614a26565b810190614ad9565b9138614b6b565b82513d6000823e3d90fd5b6001600160a01b03168060405191614d6a836149d2565b602a8352602083016040368237835115614e5e5760309053825160019060011015614e5e57607860218501536029905b808211614de3575050614dab575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614e49577f3031323334353637383961626364656600000000000000000000000000000000901a614e1f8487615a3e565b5360041c918015614e34576000190190614d9a565b60246000634e487b7160e01b81526011600452fd5b60246000634e487b7160e01b81526032600452fd5b634e487b7160e01b600052603260045260246000fd5b6000809160405160208101906395d89b4160e01b825260048152614e9781614a0a565b51915afa614ea3614aa9565b90158015614f43575b614f095780602080614ec393518301019101614ad9565b601e815111600014614b385750604051614edc81614a0a565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614f1681614a0a565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614eac565b60405190614f5c82614a0a565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f9582614a0a565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b60058110156150a75760048103614fdb5750614b38614f88565b6003810361501d5750604051614ff081614a0a565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b6001810361505f575060405161503281614a0a565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361506e57614b38614f4f565b60405161507a81614a0a565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b600052602160045260246000fd5b60405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150f581614a0a565b6000928392839251915afa615108614aa9565b908061513f575b1561513b5760208180518101031261513757602001519060ff82168203615134575090565b80fd5b5080fd5b5090565b50602081511461510f565b6040519061515782614a0a565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b6040519061519082614a0a565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906152249294936040519586926020946151de81518092888089019101614952565b84016151f282518093888085019101614952565b0161520582518093878085019101614952565b0161521882518093868085019101614952565b01038085520183614a26565b565b80156155365760009180615511575090505b60019080828110156152a25750505061524f615183565b614b3860226040518361526c829551809260208086019101614952565b81017f20310000000000000000000000000000000000000000000000000000000000006020820152036002810184520182614a26565b66038d7ea4c6800011156154b45760409081519060a0820182811067ffffffffffffffff82111761444b578084526152d9816149b6565b6000815282528251906152eb82614a0a565b8482526020917f4b000000000000000000000000000000000000000000000000000000000000008382015282840152835161532581614a0a565b8581527f4d000000000000000000000000000000000000000000000000000000000000008382015284840152835161535c81614a0a565b8581527f4200000000000000000000000000000000000000000000000000000000000000838201526060840152835161539481614a0a565b8581527f5400000000000000000000000000000000000000000000000000000000000000838201526080840152600091856000965b615488575b508451946153db86614a0a565b600790600787527f2623383830353b0000000000000000000000000000000000000000000000000083880152519560005b828110615475575050505061545661545c917f200000000000000000000000000000000000000000000000000000000000000060278701526008865261545186614a0a565b615736565b91615a4f565b916005851015614e5e57614b389460051b0151926151bc565b818101840151888201850152830161540c565b9591926103e8908185106154ab57508680916064600a87040695049301966153c9565b939296506153ce565b50506154be61514a565b614b386028604051836154db829551809260208086019101614952565b81017f203939392e3939540000000000000000000000000000000000000000000000006020820152036008810184520182614a26565b600a0a918215615522575004615238565b80634e487b7160e01b602492526012600452fd5b505060405161554481614a0a565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b62015180910304806155d95750615586615183565b614b386026604051836155a3829551809260208086019101614952565b81017f20312044617900000000000000000000000000000000000000000000000000006020820152036006810184520182614a26565b61270f81116156a8576001810361566557614b38602061562d6040516155fe81614a0a565b600481527f20446179000000000000000000000000000000000000000000000000000000008382015293615736565b60405193816156458693518092868087019101614952565b820161565982518093868085019101614952565b01038084520182614a26565b614b38602061562d60405161567981614a0a565b600581527f20446179730000000000000000000000000000000000000000000000000000008382015293615736565b506156b161514a565b614b38602a604051836156ce829551809260208086019101614952565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a810184520182614a26565b9061570e82614a8d565b61571b6040519182614a26565b828152809261572c601f1991614a8d565b0190602036910137565b806000917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000080821015615879575b506d04ee2d6d415b85acef81000000008083101561586a575b50662386f26fc100008083101561585b575b506305f5e1008083101561584c575b506127108083101561583d575b50606482101561582d575b600a80921015615823575b6001908160216157ce60018701615704565b95860101905b6157e0575b5050505090565b600019019083907f30313233343536373839616263646566000000000000000000000000000000008282061a83530491821561581e579190826157d4565b6157d9565b91600101916157bc565b91906064600291049101916157b1565b600491939204910191386157a6565b60089193920491019138615799565b6010919392049101913861578a565b60209193920491019138615778565b60409350810491503861575f565b908151156159fd576040519161589c836149d2565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805192600291600285018095116159e75760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036159e75761593a9060029694961b615704565b926020840192829183518401976020890192835194600085525b8a811061599a575050505060039394959650525106806001146159875760021461597c575090565b603d90600019015390565b50603d9081600019820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c168701015187850153168401015185820153019699615954565b634e487b7160e01b600052601160045260246000fd5b9050604051615a0b816149b6565b6000815290565b9081518151908181149384615a28575050505090565b60209293945082012092012014388080806157d9565b908151811015614e5e570160200190565b80615a615750604051615a0b816149b6565b600a811015615ac657615a7390615736565b614b38602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615ab68151809260208686019101614952565b8101036002810184520182614a26565b615acf90615736565b614b38602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615b128151809260208686019101614952565b8101036001810184520182614a26565b60405190615b2f82614a0a565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d8d57615b69615b22565b906127109081039081116159e757614b3891615b8761013692615736565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615c13815180926020605788019101614952565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c9b82518093602060a785019101614952565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615cfc82518093602060d585019101614952565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b61013282015203610116810184520182614a26565b5050604051615a0b816149b6565b6030615224919392936040519481615dbd879351809260208087019101614952565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615df48251809360208785019101614952565b01036010810185520183614a26565b6025615224919392936040519481615e25879351809260208087019101614952565b820164010714051160dd1b6020820152615e488251809360208785019101614952565b01036005810185520183614a26565b60009080518015615ecd57906000916000915b818310615e7c57505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eaf8785615a3e565b511614615ec5575b600d01936001019190615e6a565b849350615eb7565b505050600090565b60009080518015615ecd57906000916000915b818310615efa5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f2d8785615a3e565b511614615f43575b601001936001019190615ee8565b849350615f3556fea164736f6c6343000817000a"; + hex"6080806040523461001757615ec990816200001c8239f35b5f80fdfe600436101561000c575f80fd5b5f3560e01c63e9dc63751461001f575f80fd5b3461440f57604036600319011261440f576001600160a01b03600435166004350361440f576102206040525f6080819052606060a081905260c082905260e08290526101008190526101208190526101608190526101808190526101a08190526101c0526101e0819052610200526004356001600160a01b038116610140526100a790614b17565b610160526100bf6004356001600160a01b0316614d2d565b61018052610140516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f916148e8575b506001600160a01b0361012f911680608052614e35565b60a052610140516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561441b576fffffffffffffffffffffffffffffffff915f916148c9575b501660c052610140516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561441b575f9061488c575b6101fb9150614f80565b6101a052610140516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f9161485d575b5060c0516fffffffffffffffffffffffffffffffff168015614849576fffffffffffffffffffffffffffffffff6127108193021604166101606080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102cb81614977565b51902061040b60296102ed63ffffffff61016861ffff8660101c1606166156ca565b61031b63ffffffff601e604660ff6103118460146050848d60081c160601166156ca565b98160601166156ca565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261035b815180926020602488019101614931565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610397825180936020602585019101614931565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103d58351809460206027868601019101614931565b01017f25290000000000000000000000000000000000000000000000000000000000006027820152036009810184520182614a03565b6104436fffffffffffffffffffffffffffffffff6040608001511660ff61043c6001600160a01b036080511661507a565b16906151d7565b6104576001600160a01b0360805116614d2d565b90602060800151602460206001600160a01b0360c06080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa801561441b576024915f9161482a575b5060206001600160a01b0360c06080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa801561441b5761051b925f916147fb575b5064ffffffffff8091169116615505565b610180516101e0519092916105a56021610542606461053b8187066159c7565b95046156ca565b604051948161055b879351809260208087019101614931565b82016105708251809360208085019101614931565b017f25000000000000000000000000000000000000000000000000000000000000006020820152036001810185520183614a03565b6101606080015192610120608001519660e06080015196604051998a61014081011067ffffffffffffffff6101408d01111761442e576101408b016040528a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c08301111761442e576101c08101604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a08201516106aa60c0840151845190615ad3565b9061099061015c604051926106be846149e7565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526107006040516106f781614993565b5f81528661598a565b156147f3576090945b610712866156ca565b916040519586938493661e339034b21e9160c91b602086015261095e8351958692610744846027840160208901614931565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b6035858401015261078b8551809660206042888701019101614931565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661089191889160f990910190602001614931565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761092c91899161015190910190602001614931565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614931565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c81019091520182614a03565b6101008301526101208201526028610120830151604051906109b182614993565b5f8252610c5661015c604051926109c7846149e7565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109fa84615dcf565b610a0382615e49565b808211156147eb5750945b610a198787016156ca565b91604051958693661e339034b21e9160c91b60208601528151610a43816027880160208601614931565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a86825180936020604285019101614931565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b8282518093602060f985019101614931565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c1182518093602061015185019101614931565b01661e17ba32bc3a1f60c91b610151820152610c3882518093602061015885019101614931565b01631e17b39f60e11b6101588201520361013c810184520182614a03565b610160840152016101808201526028602083015160405190610c7782614993565b5f8252610cc061015c60405192610c8d846149e7565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109fa84615dcf565b8352016020820152610ffa60808301516030604051610cde81614993565b5f8152610f8461015c60405194610cf4866149e7565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d2786615dcf565b610d3082615e49565b808211156147e35750935b610d47602886016156ca565b91604051978893661e339034b21e9160c91b60208601528151610d71816027880160208601614931565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610db4825180936020604285019101614931565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610eb082518093602060f985019101614931565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f3f82518093602061015185019101614931565b01661e17ba32bc3a1f60c91b610151820152610f6682518093602061015885019101614931565b01631e17b39f60e11b6101588201520361013c810186520184614a03565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e084015261010083015161016084015184519161516d565b6060820152604051908161010081011067ffffffffffffffff6101008401111761442e57610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161012084015191606081015194604051611150816149af565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051968761014081011067ffffffffffffffff6101408a01111761442e57610140880160405261011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b01111761442e576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761442e57611ca5611d069160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261185c615a9a565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d0160d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161198e60b88660208501936118ce81605e840187614931565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611933825180936020609385019101614931565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a7820152036098810188520186614a03565b611996615a9a565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119fc81606b8a0184614931565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a41825180936020608e85019101614931565b019082608e830152611a8560a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b520189614a03565b611bcb610108611a93615a9a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b1f815180926020607387019101614931565b8201908760738301526076820152875190611b3e826096830188614931565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a614a03565b611bd3615a9a565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614931565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611ce782518093602060c485019101614931565b019160c483015260c78201520360b8810187520185614a03565b61516d565b92611d18611d12614f0e565b8961598a565b9788156147c8575b50604051611d2d816149cb565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c08701111761442e576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152895f146145a35760405161215a81614993565b5f8152995b1561444257604051806101e081011067ffffffffffffffff6101e08301111761442e576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761442e57613b6c9c612e276036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ef89f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612dc38151809260208a8c019101614931565b8701612dd88251809360208a85019101614931565b01612dec8251809360208985019101614931565b01612e008251809360208885019101614931565b01612e148251809360208785019101614931565b0191820152036016810186520184614a03565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e6c6026998260208c9451948593019101614931565b8901612e818251809360208c85019101614931565b01612e958251809360208b85019101614931565b01612ea98251809360208a85019101614931565b01612ebd8251809360208985019101614931565b01612ed18251809360208885019101614931565b01612ee58251809360208785019101614931565b019182015203600d810189520187614a03565b61378b604c60e0830151610100840151936134e761311a6060604084015193015196612f248186615d13565b9461311561012b604051612f37816149e7565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fa1815180926020603787019101614931565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130e591849161012090910190602001614931565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b81019091520187614a03565b615d13565b956132f961012b60405161312d816149e7565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613197815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132d482518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a520188614a03565b6133038184615d7b565b926134e261012b604051613316816149e7565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613380815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134bd82518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810187520185614a03565b615d7b565b906136c661012b6040516134fa816149e7565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613564815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136a182518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810185520183614a03565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261372c815180926020604589019101614931565b8401613742825180936020604585019101614931565b01613757825180936020604585019101614931565b0161376c825180936020604585019101614931565b01661e17ba32bc3a1f60c91b604582015203602c810184520182614a03565b613a6b61019a6101408401516101a0850151906137cc6137c66137c06137ba60e060408b01519a0151946156ca565b946156ca565b976156ca565b916156ca565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e86015261012790613967815180926020858a019101614931565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139d18251809360208b85019101614931565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a148251809360208985019101614931565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a578251809360208785019101614931565b01918201520361017a810185520183614a03565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613af7815180926020607b89019101614931565b8401613b0d825180936020607b85019101614931565b01613b22825180936020607b85019101614931565b01613b37825180936020607b85019101614931565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b820152036061810184520182614a03565b610140608001525f806001600160a01b0360c0608001511660405160208101907fb2564569000000000000000000000000000000000000000000000000000000008252602435602482015260248152613bc4816149af565b51915afa613bd0614a86565b61012081905290158015610200526144265760208180518101031261440f5760200151801515810361440f575b151560e05260a051610140516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f916143d1575b506141e26142d3609461434594613d9b6089613c786142de97614d2d565b92610120608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613cc0815180926020604088019101614931565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613d25825180936020606385019101614931565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d66825180936020608685019101614931565b017f227d5d00000000000000000000000000000000000000000000000000000000006086820152036069810184520182614a03565b6101605160a0516101805160805190926140cc9160e39190613dc5906001600160a01b0316614d2d565b94613dd16024356156ca565b60e0519096901561434957604051613de8816149cb565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461406860208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613f188160558c0184614931565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613fa28260b183018a614931565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613fdd82518093602060c385019101614931565b016140167f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614931565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c782015261405482518093602060d185019101614931565b019260d184015251809360d5840190614931565b019060d582015261408382518093602060df85019101614931565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140bd8251809360208785019101614931565b010360c3810185520183614a03565b610160519061423d6140df6024356156ca565b9161415e602d604051809560208201976a029b0b13634b2b9102b19160ad1b8952614114815180926020602b87019101614931565b82017f2023000000000000000000000000000000000000000000000000000000000000602b82015261414f8251809360208785019101614931565b0103600d810186520184614a03565b6101c05161416b90615819565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a01526141ac815180926020602e8d019101614931565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614931565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614931565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d82015261429e825180936020609285019101614931565b017f227d0000000000000000000000000000000000000000000000000000000000006092820152036074810184520182614a03565b610100819052615819565b614331603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526143218151809260208686019101614931565b810103601d810184520182614a03565b604051918291602083526020830190614952565b0390f35b60405161435581614977565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613eac565b90506020813d602011614413575b816143ec60209383614a03565b8101031261440f5751906001600160a01b038216820361440f57906141e2613c5a565b5f80fd5b3d91506143df565b6040513d5f823e3d90fd5b506001613bfd565b634e487b7160e01b5f52604160045260245ffd5b6040518061012081011067ffffffffffffffff6101208301111761442e57610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123ac565b604051806101c081011067ffffffffffffffff6101c08301111761442e576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a08201529961215f565b6147dc9198506147d6614f47565b9061598a565b965f611d20565b905093610d3b565b905094610a0e565b60d094610709565b61481d915060203d602011614823575b6148158183614a03565b810190614a4d565b5f61050a565b503d61480b565b614843915060203d602011614823576148158183614a03565b5f6104b4565b634e487b7160e01b5f52601260045260245ffd5b61487f915060203d602011614885575b6148778183614a03565b810190614a25565b5f610254565b503d61486d565b506020813d6020116148c1575b816148a660209383614a03565b8101031261440f5751600581101561440f576101fb906101f1565b3d9150614899565b6148e2915060203d602011614885576148778183614a03565b5f610198565b90506020813d602011614929575b8161490360209383614a03565b8101031261440f57516001600160a01b038116810361440f576001600160a01b03610118565b3d91506148f6565b5f5b8381106149425750505f910152565b8181015183820152602001614933565b9060209161496b81518092818552858086019101614931565b601f01601f1916010190565b6080810190811067ffffffffffffffff82111761442e57604052565b6020810190811067ffffffffffffffff82111761442e57604052565b6060810190811067ffffffffffffffff82111761442e57604052565b60c0810190811067ffffffffffffffff82111761442e57604052565b6040810190811067ffffffffffffffff82111761442e57604052565b90601f8019910116810190811067ffffffffffffffff82111761442e57604052565b9081602091031261440f57516fffffffffffffffffffffffffffffffff8116810361440f5790565b9081602091031261440f575164ffffffffff8116810361440f5790565b67ffffffffffffffff811161442e57601f01601f191660200190565b3d15614ab0573d90614a9782614a6a565b91614aa56040519384614a03565b82523d5f602084013e565b606090565b60208183031261440f5780519067ffffffffffffffff821161440f570181601f8201121561440f578051614ae881614a6a565b92614af66040519485614a03565b8184526020828401011161440f57614b149160208085019101614931565b90565b6001600160a01b031660408051916395d89b4160e01b83525f83600481845afa928315614d23575f93614cff575b50815192614b52846149e7565b60118452614b876020947f5341422d56322d4c4f434b55502d4c494e000000000000000000000000000000868201528261598a565b15614bc55750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614bbb836149e7565b600d835282015290565b614c028351614bd3816149e7565b601181527f5341422d56322d4c4f434b55502d44594e000000000000000000000000000000868201528261598a565b15614c405750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c36836149e7565b600e835282015290565b614c7d8351614c4e816149e7565b601181527f5341422d56322d4c4f434b55502d545241000000000000000000000000000000868201528261598a565b15614cbb5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614cb1836149e7565b600f835282015290565b614cfb9083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614952565b0390fd5b614d1c9193503d805f833e614d148183614a03565b810190614ab5565b915f614b45565b82513d5f823e3d90fd5b6001600160a01b03168060405191614d44836149af565b602a8352602083016040368237835115614e215760309053825160019060011015614e2157607860218501536029905b808211614dbd575050614d85575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614e21577f3031323334353637383961626364656600000000000000000000000000000000901a614df984876159b6565b5360041c918015614e0d575f190190614d74565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614e57816149e7565b51915afa614e63614a86565b90158015614f02575b614ec85780602080614e8393518301019101614ab5565b601e8151115f14614b145750604051614e9b816149e7565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614ed5816149e7565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614e6c565b60405190614f1b826149e7565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f54826149e7565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b60058110156150665760048103614f9a5750614b14614f47565b60038103614fdc5750604051614faf816149e7565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b6001810361501e5750604051614ff1816149e7565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361502d57614b14614f0e565b604051615039816149e7565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150b5816149e7565b51915afa6150c1614a86565b90806150f0575b156150eb5760208180518101031261440f576020015160ff8116810361440f5790565b505f90565b5060208151146150c8565b60405190615108826149e7565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615141826149e7565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151d592949360405195869260209461518f81518092888089019101614931565b84016151a382518093888085019101614931565b016151b682518093878085019101614931565b016151c982518093868085019101614931565b01038085520183614a03565b565b9081156154ca57806154ba57505b600190808281101561524f575050506151fc615134565b614b14602260405183615219829551809260208086019101614931565b81017f20310000000000000000000000000000000000000000000000000000000000006020820152036002810184520182614a03565b66038d7ea4c68000111561545d5760409081519060a0820182811067ffffffffffffffff82111761442e5780845261528681614993565b5f81528252825190615297826149e7565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152d1816149e7565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615308816149e7565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615340816149e7565b8581527f54000000000000000000000000000000000000000000000000000000000000008382015260808401525f91855f965b615431575b50845194615385866149e7565b600790600787527f2623383830353b000000000000000000000000000000000000000000000000008388015251955f5b82811061541e57505050506153ff615405917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526153fa866149e7565b6156ca565b916159c7565b916005851015614e2157614b149460051b01519261516d565b81810184015188820185015283016153b5565b9591926103e89081851061545457508680916064600a8704069504930196615373565b93929650615378565b50506154676150fb565b614b14602860405183615484829551809260208086019101614931565b81017f203939392e3939540000000000000000000000000000000000000000000000006020820152036008810184520182614a03565b600a0a90811561484957046151e5565b50506040516154d8816149e7565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061556d575061551a615134565b614b14602660405183615537829551809260208086019101614931565b81017f20312044617900000000000000000000000000000000000000000000000000006020820152036006810184520182614a03565b61270f811161563c57600181036155f957614b1460206155c1604051615592816149e7565b600481527f204461790000000000000000000000000000000000000000000000000000000083820152936156ca565b60405193816155d98693518092868087019101614931565b82016155ed82518093868085019101614931565b01038084520182614a03565b614b1460206155c160405161560d816149e7565b600581527f204461797300000000000000000000000000000000000000000000000000000083820152936156ca565b506156456150fb565b614b14602a60405183615662829551809260208086019101614931565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a810184520182614a03565b906156a282614a6a565b6156af6040519182614a03565b82815280926156c0601f1991614a6a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561580b575b506d04ee2d6d415b85acef8100000000808310156157fc575b50662386f26fc10000808310156157ed575b506305f5e100808310156157de575b50612710808310156157cf575b5060648210156157bf575b600a809210156157b5575b60019081602161576160018701615698565b95860101905b615773575b5050505090565b5f19019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157b057919082615767565b61576c565b916001019161574f565b9190606460029104910191615744565b6004919392049101915f615739565b6008919392049101915f61572c565b6010919392049101915f61571d565b6020919392049101915f61570b565b60409350810491505f6156f2565b90815115615976576040519161582e836149af565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604084015280519260029160028501809511614e0d5760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614e0d576158cc9060029694961b615698565b9260208401928291835184019760208901928351945f85525b8a8110615929575050505060039394959650525106806001146159175760021461590d575090565b603d905f19015390565b50603d90815f19820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c1687010151878501531684010151858201530196996158e5565b905060405161598481614993565b5f815290565b90815181519081811493846159a0575050505090565b602092939450820120920120145f80808061576c565b908151811015614e21570160200190565b806159d9575060405161598481614993565b600a811015615a3e576159eb906156ca565b614b14602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a2e8151809260208686019101614931565b8101036002810184520182614a03565b615a47906156ca565b614b14602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a8a8151809260208686019101614931565b8101036001810184520182614a03565b60405190615aa7826149e7565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d0557615ae1615a9a565b90612710908103908111614e0d57614b1491615aff610136926156ca565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615b8b815180926020605788019101614931565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c1382518093602060a785019101614931565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615c7482518093602060d585019101614931565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b61013282015203610116810184520182614a03565b505060405161598481614993565b60306151d5919392936040519481615d35879351809260208087019101614931565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615d6c8251809360208785019101614931565b01036010810185520183614a03565b60256151d5919392936040519481615d9d879351809260208087019101614931565b820164010714051160dd1b6020820152615dc08251809360208785019101614931565b01036005810185520183614a03565b5f9080518015615e4257905f915f915b818310615df157505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e2487856159b6565b511614615e3a575b600d01936001019190615ddf565b849350615e2c565b5050505f90565b5f9080518015615e4257905f915f915b818310615e6b5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e9e87856159b6565b511614615eb4575b601001936001019190615e59565b849350615ea656fea164736f6c6343000817000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS From 48c689a95737e23b517468c2702740cf9b4c66b4 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 16 May 2024 22:00:09 +0100 Subject: [PATCH 100/132] refactor: polish update-counts script refacotr: bnb instead of bsc refactor: tranche instead of tranch refactor: various misc improvements --- .env.deployment.example | 2 +- benchmark/EstimateMaxCount.t.sol | 2 +- script/Base.s.sol | 10 ++++---- shell/deploy-multi-chain.sh | 4 ++-- ...date-script-counts.sh => update-counts.sh} | 24 +++++++++---------- test/Base.t.sol | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) rename shell/{update-script-counts.sh => update-counts.sh} (85%) diff --git a/.env.deployment.example b/.env.deployment.example index 39ff9e303..30200b552 100644 --- a/.env.deployment.example +++ b/.env.deployment.example @@ -9,7 +9,7 @@ export ARBITRUM_RPC_URL="YOUR_RPC_URL" export ARBITRUM_SEPOLIA_RPC_URL="YOUR_RPC_URL" export AVALANCHE_RPC_URL="YOUR_RPC_URL" export BASE_RPC_URL="YOUR_RPC_URL" -export BSC_RPC_URL="YOUR_RPC_URL" +export BNB_RPC_URL="YOUR_RPC_URL" export GNOSIS_RPC_URL="YOUR_RPC_URL" export MAINNET_RPC_URL="YOUR_RPC_URL" export OPTIMISM_RPC_URL="YOUR_RPC_URL" diff --git a/benchmark/EstimateMaxCount.t.sol b/benchmark/EstimateMaxCount.t.sol index 006ed36cc..792f8ad80 100644 --- a/benchmark/EstimateMaxCount.t.sol +++ b/benchmark/EstimateMaxCount.t.sol @@ -28,7 +28,7 @@ contract EstimateMaxCount is Test { chains.push(ChainInfo({ blockGasLimit: 15_000_000, chainId: 43_114 })); // Avalanche chains.push(ChainInfo({ blockGasLimit: 60_000_000, chainId: 8453 })); // Base chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 238 })); // Blast - chains.push(ChainInfo({ blockGasLimit: 138_000_000, chainId: 56 })); // BSC + chains.push(ChainInfo({ blockGasLimit: 138_000_000, chainId: 56 })); // BNB chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 1 })); // Ethereum chains.push(ChainInfo({ blockGasLimit: 17_000_000, chainId: 100 })); // Gnosis chains.push(ChainInfo({ blockGasLimit: 30_000_000, chainId: 10 })); // Optimism diff --git a/script/Base.s.sol b/script/Base.s.sol index 2097ae5cf..9cdc3bdcf 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -56,9 +56,9 @@ contract BaseScript is Script { } // Populate the segment and tranche count map. - populateSegmentAndTranchCountMap(); + populateSegmentAndTrancheCountMap(); - // If there is no maximum value set for a specific chain, set a default value. + // If there is no maximum value set for a specific chain, use the default value. if (segmentCountMap[block.chainid] == 0) { maxSegmentCount = DEFAULT_MAX_COUNT; } @@ -88,8 +88,8 @@ contract BaseScript is Script { return bytes32(abi.encodePacked(create2Salt)); } - /// @dev Populates the segment & tranche count map. Values are auto updated by the `update-script-counts.sh` script. - function populateSegmentAndTranchCountMap() internal { + /// @dev Populates the segment & tranche count map. Values can be updated using the `update-counts.sh` script. + function populateSegmentAndTrancheCountMap() internal { // Arbitrum chain ID segmentCountMap[42_161] = 1170; trancheCountMap[42_161] = 1210; @@ -106,7 +106,7 @@ contract BaseScript is Script { segmentCountMap[238] = 1100; trancheCountMap[238] = 1130; - // BSC chain ID. + // BNB chain ID. segmentCountMap[56] = 4870; trancheCountMap[56] = 5180; diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 1b7e246e2..c21ea7b6c 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -65,7 +65,7 @@ export ARBITRUM_ADMIN="0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376" export ARBITRUM_SEPOLIA_ADMIN="0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F" export AVALANCHE_ADMIN="0x4735517616373c5137dE8bcCDc887637B8ac85Ce" export BASE_ADMIN="0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66" -export BSC_ADMIN="0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3" +export BNB_ADMIN="0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3" export GNOSIS_ADMIN="0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399" export MAINNET_ADMIN="0x79Fb3e81aAc012c08501f41296CCC145a1E15844" export OPTIMISM_ADMIN="0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350" @@ -107,7 +107,7 @@ function initialize { chains["arbitrum_sepolia"]="$ARBITRUM_SEPOLIA_RPC_URL $ARBISCAN_API_KEY $ARBITRUM_SEPOLIA_ADMIN" chains["avalanche"]="$AVALANCHE_RPC_URL $SNOWTRACE_API_KEY $AVALANCHE_ADMIN" chains["base"]="$BASE_RPC_URL $BASESCAN_API_KEY $BASE_ADMIN" - chains["bnb_smart_chain"]="$BSC_RPC_URL $BSCSCAN_API_KEY $BSC_ADMIN" + chains["bnb_smart_chain"]="$BNB_RPC_URL $BSCSCAN_API_KEY $BNB_ADMIN" chains["gnosis"]="$GNOSIS_RPC_URL $GNOSISSCAN_API_KEY $GNOSIS_ADMIN" chains["mainnet"]="$MAINNET_RPC_URL $ETHERSCAN_API_KEY $MAINNET_ADMIN" chains["optimism"]="$OPTIMISM_RPC_URL $OPTIMISTIC_API_KEY $OPTIMISM_ADMIN" diff --git a/shell/update-script-counts.sh b/shell/update-counts.sh similarity index 85% rename from shell/update-script-counts.sh rename to shell/update-counts.sh index 15dfbe0f9..6a230a024 100755 --- a/shell/update-script-counts.sh +++ b/shell/update-counts.sh @@ -8,13 +8,19 @@ # Strict mode set -euo pipefail -# Path to the Solidity file -BASE_SCRIPT_FILE="script/Base.s.sol" +# Path to the Base Script +BASE_SCRIPT="script/Base.s.sol" -# Compile the contracts with optimized profile +# Compile the contracts with the optimized profile bun run build:optimized -# Generalized function to update counts in the solidity file +# Helper function to format chain IDs with underscores +format_chain_id() { + local id=$1 + [[ ${#id} -gt 4 ]] && echo $id | rev | sed 's/\(...\)/\1_/g' | rev | sed 's/^_//' || echo $id +} + +# Generalized function to update counts update_counts() { local test_name=$1 local map_name=$2 @@ -35,24 +41,18 @@ update_counts() { table+="\n$map_name,$formatted_chain_id,$count" # Update the map for each chain ID using sd - sd "$map_name\[$formatted_chain_id\] = [0-9_]+;" "$map_name[$formatted_chain_id] = $count;" $BASE_SCRIPT_FILE + sd "$map_name\[$formatted_chain_id\] = [0-9_]+;" "$map_name[$formatted_chain_id] = $count;" $BASE_SCRIPT done < <(echo "$output" | grep 'count:') # Print the table using the column command echo -e $table | column -t -s ',' } -# Helper function to format chain IDs with underscores -format_chain_id() { - local id=$1 - [[ ${#id} -gt 4 ]] && echo $id | rev | sed 's/\(...\)/\1_/g' | rev | sed 's/^_//' || echo $id -} - # Call the function with specific parameters for segments and tranches update_counts "Segments" "segmentCountMap" update_counts "Tranches" "trancheCountMap" # Reformat the code with Forge -forge fmt $BASE_SCRIPT_FILE +forge fmt $BASE_SCRIPT printf "\n\nAll mappings updated." diff --git a/test/Base.t.sol b/test/Base.t.sol index 2bd58e9af..1dffc586d 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -124,7 +124,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi /// deployer's nonce, which would in turn lead to different addresses (recall that the addresses /// for contracts deployed via `CREATE` are based on the caller-and-nonce-hash). function deployCoreConditionally() internal { - if (!isTestOptimizedProfile() && !isBenchmarkProfile()) { + if (!isBenchmarkProfile() && !isTestOptimizedProfile()) { nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); From 2f88291ae140c96cdf43fb1534699f15cb492ded Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 17 May 2024 10:45:30 +0100 Subject: [PATCH 101/132] fix: replace maxSegmentCoun/maxTrancheCount with segmentCountMap/trancheCountMap (#928) --- script/Base.s.sol | 12 +++--------- script/DeployCore.s.sol | 4 ++-- script/DeployCore2.s.sol | 4 ++-- script/DeployDeterministicCore.s.sol | 6 ++++-- script/DeployDeterministicCore2.s.sol | 6 ++++-- script/DeployDeterministicLockupDynamic.s.sol | 3 ++- script/DeployDeterministicLockupTranched.s.sol | 4 +++- script/DeployLockupDynamic.s.sol | 2 +- script/DeployLockupTranched.s.sol | 2 +- 9 files changed, 22 insertions(+), 21 deletions(-) diff --git a/script/Base.s.sol b/script/Base.s.sol index 2097ae5cf..41480d3f5 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -12,7 +12,7 @@ contract BaseScript is Script { using Strings for uint256; using stdJson for string; - /// @dev The default value for `maxSegmentCount` and `maxTrancheCount`. + /// @dev The default value for `segmentCountMap` and `trancheCountMap`. uint256 internal constant DEFAULT_MAX_COUNT = 500; /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. @@ -24,12 +24,6 @@ contract BaseScript is Script { /// @dev The address of the transaction broadcaster. address internal broadcaster; - /// @dev The upper limit on the length of segments to ensure that transactions stay within the block gas limit. - uint256 internal maxSegmentCount; - - /// @dev The upper limit on the length of tranches to ensure that transactions stay within the block gas limit. - uint256 internal maxTrancheCount; - /// @dev Used to derive the broadcaster's address if $EOA is not defined. string internal mnemonic; @@ -60,10 +54,10 @@ contract BaseScript is Script { // If there is no maximum value set for a specific chain, set a default value. if (segmentCountMap[block.chainid] == 0) { - maxSegmentCount = DEFAULT_MAX_COUNT; + segmentCountMap[block.chainid] = DEFAULT_MAX_COUNT; } if (trancheCountMap[block.chainid] == 0) { - maxTrancheCount = DEFAULT_MAX_COUNT; + trancheCountMap[block.chainid] = DEFAULT_MAX_COUNT; } } diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index d3c059a8b..36deb6db5 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -28,8 +28,8 @@ contract DeployCore is BaseScript { ) { nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 2bdc13422..0bcf8b416 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -28,8 +28,8 @@ contract DeployCore2 is BaseScript { SablierV2LockupTranched lockupTranched ) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index 145a6d819..cf943cf2a 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -31,8 +31,10 @@ contract DeployDeterministicCore is BaseScript { { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxSegmentCount); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxTrancheCount); + lockupTranched = + new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index d3603f1c8..cab3694f3 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -31,8 +31,10 @@ contract DeployDeterministicCore2 is BaseScript { ) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, maxSegmentCount); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, maxTrancheCount); + lockupTranched = + new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 55dafd211..799233f41 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -20,6 +20,7 @@ contract DeployDeterministicLockupDynamic is BaseScript { returns (SablierV2LockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); - lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, maxSegmentCount); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); } } diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index d3b3485f6..e06636209 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -20,6 +20,8 @@ contract DeployDeterministicLockupTranched is BaseScript { returns (SablierV2LockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); - lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, maxTrancheCount); + lockupTranched = new SablierV2LockupTranched{ salt: salt }( + initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid] + ); } } diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index 25a77fd98..154215b9f 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -17,6 +17,6 @@ contract DeployLockupDynamic is BaseScript { broadcast returns (SablierV2LockupDynamic lockupDynamic) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, maxSegmentCount); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); } } diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 08bdfbc65..76d1ccadd 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -17,6 +17,6 @@ contract DeployLockupTranched is BaseScript { broadcast returns (SablierV2LockupTranched lockupTranched) { - lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, maxTrancheCount); + lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid]); } } From f71eb9d3333e04aa0c853b162dc6245fe93db07b Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 20 May 2024 13:35:18 +0300 Subject: [PATCH 102/132] Update count script improvements (#931) * chore: use "forgefmt: disable-start" in Base.s.sol chore: remove format_chain_id function from update counts bash script * style: add forgefmt disable block --------- Co-authored-by: smol-ninja --- script/Base.s.sol | 20 ++++++++++++-------- shell/update-counts.sh | 14 ++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/script/Base.s.sol b/script/Base.s.sol index 891e17a89..647a17c20 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -84,13 +84,15 @@ contract BaseScript is Script { /// @dev Populates the segment & tranche count map. Values can be updated using the `update-counts.sh` script. function populateSegmentAndTrancheCountMap() internal { + // forgefmt: disable-start + // Arbitrum chain ID - segmentCountMap[42_161] = 1170; - trancheCountMap[42_161] = 1210; + segmentCountMap[42161] = 1170; + trancheCountMap[42161] = 1210; // Avalanche chain ID. - segmentCountMap[43_114] = 530; - trancheCountMap[43_114] = 540; + segmentCountMap[43114] = 530; + trancheCountMap[43114] = 540; // Base chain ID. segmentCountMap[8453] = 2200; @@ -121,11 +123,13 @@ contract BaseScript is Script { trancheCountMap[137] = 1130; // Scroll chain ID. - segmentCountMap[534_352] = 340; - trancheCountMap[534_352] = 350; + segmentCountMap[534352] = 340; + trancheCountMap[534352] = 350; // Sepolia chain ID. - segmentCountMap[11_155_111] = 1100; - trancheCountMap[11_155_111] = 1130; + segmentCountMap[11155111] = 1100; + trancheCountMap[11155111] = 1130; + + // forgefmt: disable-end } } diff --git a/shell/update-counts.sh b/shell/update-counts.sh index 6a230a024..a865a3f4e 100755 --- a/shell/update-counts.sh +++ b/shell/update-counts.sh @@ -14,12 +14,6 @@ BASE_SCRIPT="script/Base.s.sol" # Compile the contracts with the optimized profile bun run build:optimized -# Helper function to format chain IDs with underscores -format_chain_id() { - local id=$1 - [[ ${#id} -gt 4 ]] && echo $id | rev | sed 's/\(...\)/\1_/g' | rev | sed 's/^_//' || echo $id -} - # Generalized function to update counts update_counts() { local test_name=$1 @@ -28,20 +22,20 @@ update_counts() { local output=$(FOUNDRY_PROFILE=benchmark forge t --mt "test_Estimate${test_name}" -vv) echo -e "\nParsing output for $test_name..." - # Define a table with headers + # Define a table with headers. This table is not put in the Solidity script file, + # but is used to be displayed in the terminal. local table="Category,Chain ID,New Max Count" # Parse the output to extract counts and chain IDs while IFS= read -r line; do local count=$(echo $line | awk '{print $2}') local chain_id=$(echo $line | awk '{print $8}') - local formatted_chain_id=$(format_chain_id $chain_id) # Add the data to the table - table+="\n$map_name,$formatted_chain_id,$count" + table+="\n$map_name,$chain_id,$count" # Update the map for each chain ID using sd - sd "$map_name\[$formatted_chain_id\] = [0-9_]+;" "$map_name[$formatted_chain_id] = $count;" $BASE_SCRIPT + sd "$map_name\[$chain_id\] = [0-9]+;" "$map_name[$chain_id] = $count;" $BASE_SCRIPT done < <(echo "$output" | grep 'count:') # Print the table using the column command From 21630849eef2ccbba897b18dd5c8d0f30400323b Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 20 May 2024 16:11:31 +0100 Subject: [PATCH 103/132] test: consistent licenses in utils ci: rename step --- .github/workflows/multibuild.yml | 2 +- test/utils/BaseScript.t.sol | 2 +- test/utils/Defaults.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index ee53e7087..ddfcbefdf 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -18,7 +18,7 @@ jobs: - name: "Install the Node.js dependencies" run: "bun install --frozen-lockfile" - - name: "Check that V2 Core can be built with multiple Solidity versions" + - name: "Check that the project can be built with multiple Solidity versions" uses: "PaulRBerg/foundry-multibuild@v1" with: min: "0.8.22" diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index 65f8585fa..21a7d7fc5 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 27dca7c78..279eda4f6 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; From 56ce2b994519d327143784ef58546a401ce0507a Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 20 May 2024 16:27:16 +0100 Subject: [PATCH 104/132] test: absolute paths in precompiles test --- test/utils/Precompiles.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 50b1037ee..5dcd11e88 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -3,11 +3,11 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { Precompiles } from "../../precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { Precompiles } from "precompiles/Precompiles.sol"; +import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; From 003dc701e3877aae4690bf23436896b830cae1c4 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 23 May 2024 22:59:22 +0100 Subject: [PATCH 105/132] revert: 56ce2b9 --- test/utils/Precompiles.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 5dcd11e88..50b1037ee 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -3,11 +3,11 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { Precompiles } from "precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; +import { Precompiles } from "../../precompiles/Precompiles.sol"; +import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; From 56d0ccdcd529c29b0a21486149dbcf6f13fa8926 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sun, 26 May 2024 20:16:16 +0100 Subject: [PATCH 106/132] test(invariant): remove TimestampStore --- test/invariant/Invariant.t.sol | 23 ------------- test/invariant/Lockup.t.sol | 32 +++++++++---------- test/invariant/LockupDynamic.t.sol | 18 +++-------- test/invariant/LockupLinear.t.sol | 20 ++++-------- test/invariant/LockupTranched.t.sol | 18 +++-------- test/invariant/handlers/BaseHandler.sol | 11 ++----- .../handlers/LockupDynamicCreateHandler.sol | 10 +----- .../handlers/LockupDynamicHandler.sol | 4 +-- test/invariant/handlers/LockupHandler.sol | 10 +----- .../handlers/LockupLinearCreateHandler.sol | 10 +----- .../handlers/LockupLinearHandler.sol | 4 +-- .../handlers/LockupTranchedCreateHandler.sol | 4 +-- .../handlers/LockupTranchedHandler.sol | 4 +-- test/invariant/stores/TimestampStore.sol | 16 ---------- 14 files changed, 41 insertions(+), 143 deletions(-) delete mode 100644 test/invariant/stores/TimestampStore.sol diff --git a/test/invariant/Invariant.t.sol b/test/invariant/Invariant.t.sol index c6a0f4325..df5b9fe67 100644 --- a/test/invariant/Invariant.t.sol +++ b/test/invariant/Invariant.t.sol @@ -4,25 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { StdInvariant } from "forge-std/src/StdInvariant.sol"; import { Base_Test } from "../Base.t.sol"; -import { TimestampStore } from "./stores/TimestampStore.sol"; /// @notice Common logic needed by all invariant tests. abstract contract Invariant_Test is Base_Test, StdInvariant { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - TimestampStore internal timestampStore; - - /*////////////////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////////////////*/ - - modifier useCurrentTimestamp() { - vm.warp(timestampStore.currentTimestamp()); - _; - } - /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION //////////////////////////////////////////////////////////////////////////*/ @@ -30,15 +14,8 @@ abstract contract Invariant_Test is Base_Test, StdInvariant { function setUp() public virtual override { Base_Test.setUp(); - // Deploy the handlers. - timestampStore = new TimestampStore(); - - // Label the handlers. - vm.label({ account: address(timestampStore), newLabel: "TimestampStore" }); - // Prevent these contracts from being fuzzed as `msg.sender`. excludeSender(address(lockupDynamic)); excludeSender(address(lockupLinear)); - excludeSender(address(timestampStore)); } } diff --git a/test/invariant/Lockup.t.sol b/test/invariant/Lockup.t.sol index c6fb7d62c..bccc95c92 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/invariant/Lockup.t.sol @@ -38,7 +38,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { //////////////////////////////////////////////////////////////////////////*/ // solhint-disable max-line-length - function invariant_ContractBalance() external useCurrentTimestamp { + function invariant_ContractBalance() external view { uint256 contractBalance = dai.balanceOf(address(lockup)); uint256 lastStreamId = lockupStore.lastStreamId(); @@ -59,7 +59,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { ); } - function invariant_DepositedAmountGteStreamedAmount() external useCurrentTimestamp { + function invariant_DepositedAmountGteStreamedAmount() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -71,7 +71,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_DepositedAmountGteWithdrawableAmount() external useCurrentTimestamp { + function invariant_DepositedAmountGteWithdrawableAmount() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -83,7 +83,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_DepositedAmountGteWithdrawnAmount() external useCurrentTimestamp { + function invariant_DepositedAmountGteWithdrawnAmount() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -95,7 +95,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_DepositedAmountNotZero() external useCurrentTimestamp { + function invariant_DepositedAmountNotZero() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -104,7 +104,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_EndTimeGtStartTime() external useCurrentTimestamp { + function invariant_EndTimeGtStartTime() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -116,7 +116,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_NextStreamId() external useCurrentTimestamp { + function invariant_NextStreamId() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 nextStreamId = lockup.nextStreamId(); @@ -124,7 +124,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StartTimeNotZero() external useCurrentTimestamp { + function invariant_StartTimeNotZero() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -133,7 +133,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StatusCanceled() external useCurrentTimestamp { + function invariant_StatusCanceled() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -158,7 +158,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StatusDepleted() external useCurrentTimestamp { + function invariant_StatusDepleted() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -183,7 +183,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StatusPending() external useCurrentTimestamp { + function invariant_StatusPending() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -217,7 +217,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StatusSettled() external useCurrentTimestamp { + function invariant_StatusSettled() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -242,7 +242,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StatusStreaming() external useCurrentTimestamp { + function invariant_StatusStreaming() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -262,7 +262,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } /// @dev See diagram at https://i.postimg.cc/sfHsBkWB/mermaid-diagram-2023-04-25-190035.png. - function invariant_StatusTransitions() external useCurrentTimestamp { + function invariant_StatusTransitions() external { uint256 lastStreamId = lockupStore.lastStreamId(); if (lastStreamId == 0) { return; @@ -311,7 +311,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StreamedAmountGteWithdrawableAmount() external useCurrentTimestamp { + function invariant_StreamedAmountGteWithdrawableAmount() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -323,7 +323,7 @@ abstract contract Lockup_Invariant_Test is Invariant_Test { } } - function invariant_StreamedAmountGteWithdrawnAmount() external useCurrentTimestamp { + function invariant_StreamedAmountGteWithdrawnAmount() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/LockupDynamic.t.sol b/test/invariant/LockupDynamic.t.sol index 048f0fa74..60c7d2989 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/invariant/LockupDynamic.t.sol @@ -24,18 +24,10 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { Lockup_Invariant_Test.setUp(); // Deploy the LockupDynamic handlers. - dynamicHandler = new LockupDynamicHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupDynamic_: lockupDynamic - }); - dynamicCreateHandler = new LockupDynamicCreateHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupDynamic_: lockupDynamic - }); + dynamicHandler = + new LockupDynamicHandler({ asset_: dai, lockupStore_: lockupStore, lockupDynamic_: lockupDynamic }); + dynamicCreateHandler = + new LockupDynamicCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupDynamic_: lockupDynamic }); // Label the contracts. vm.label({ account: address(dynamicHandler), newLabel: "LockupDynamicHandler" }); @@ -59,7 +51,7 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { //////////////////////////////////////////////////////////////////////////*/ /// @dev Unordered segment timestamps are not allowed. - function invariant_SegmentTimestampsOrdered() external useCurrentTimestamp { + function invariant_SegmentTimestampsOrdered() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/LockupLinear.t.sol b/test/invariant/LockupLinear.t.sol index 17bdd4ab3..d1060ef50 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/invariant/LockupLinear.t.sol @@ -24,18 +24,10 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { Lockup_Invariant_Test.setUp(); // Deploy the lockupLinear contract handlers. - lockupLinearHandler = new LockupLinearHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupLinear_: lockupLinear - }); - lockupLinearCreateHandler = new LockupLinearCreateHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupLinear_: lockupLinear - }); + lockupLinearHandler = + new LockupLinearHandler({ asset_: dai, lockupStore_: lockupStore, lockupLinear_: lockupLinear }); + lockupLinearCreateHandler = + new LockupLinearCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupLinear_: lockupLinear }); // Label the handler contracts. vm.label({ account: address(lockupLinearHandler), newLabel: "LockupLinearHandler" }); @@ -59,7 +51,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { //////////////////////////////////////////////////////////////////////////*/ /// @dev If it is not zero, the cliff time must be strictly greater than the start time. - function invariant_CliffTimeGtStartTimeOrZero() external useCurrentTimestamp { + function invariant_CliffTimeGtStartTimeOrZero() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); @@ -74,7 +66,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { } /// @dev The end time must not be less than or equal to the cliff time. - function invariant_EndTimeGtCliffTime() external useCurrentTimestamp { + function invariant_EndTimeGtCliffTime() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/LockupTranched.t.sol b/test/invariant/LockupTranched.t.sol index 03f1d55ae..f60414f99 100644 --- a/test/invariant/LockupTranched.t.sol +++ b/test/invariant/LockupTranched.t.sol @@ -24,18 +24,10 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { Lockup_Invariant_Test.setUp(); // Deploy the LockupTranched handlers. - tranchedHandler = new LockupTranchedHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupTranched_: lockupTranched - }); - tranchedCreateHandler = new LockupTranchedCreateHandler({ - asset_: dai, - timestampStore_: timestampStore, - lockupStore_: lockupStore, - lockupTranched_: lockupTranched - }); + tranchedHandler = + new LockupTranchedHandler({ asset_: dai, lockupStore_: lockupStore, lockupTranched_: lockupTranched }); + tranchedCreateHandler = + new LockupTranchedCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupTranched_: lockupTranched }); // Label the contracts. vm.label({ account: address(tranchedHandler), newLabel: "LockupTranchedHandler" }); @@ -73,7 +65,7 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { } /// @dev Unordered tranche timestamps are not allowed. - function invariant_TrancheTimestampsOrdered() external useCurrentTimestamp { + function invariant_TrancheTimestampsOrdered() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); diff --git a/test/invariant/handlers/BaseHandler.sol b/test/invariant/handlers/BaseHandler.sol index 728809cb7..fdd804cdb 100644 --- a/test/invariant/handlers/BaseHandler.sol +++ b/test/invariant/handlers/BaseHandler.sol @@ -6,7 +6,6 @@ import { StdCheats } from "forge-std/src/StdCheats.sol"; import { Constants } from "../../utils/Constants.sol"; import { Fuzzers } from "../../utils/Fuzzers.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; /// @notice Base contract with common logic needed by all handler contracts. abstract contract BaseHandler is Constants, Fuzzers, StdCheats { @@ -30,16 +29,12 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev Default ERC-20 asset used for testing. IERC20 public asset; - /// @dev Reference to the timestamp store, which is needed for simulating the passage of time. - TimestampStore public timestampStore; - /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, TimestampStore timestampStore_) { + constructor(IERC20 asset_) { asset = asset_; - timestampStore = timestampStore_; } /*////////////////////////////////////////////////////////////////////////// @@ -47,12 +42,10 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { //////////////////////////////////////////////////////////////////////////*/ /// @dev Simulates the passage of time. The time jump is upper bounded so that streams don't settle too quickly. - /// See https://github.com/foundry-rs/foundry/issues/4994. /// @param timeJumpSeed A fuzzed value needed for generating random time warps. modifier adjustTimestamp(uint256 timeJumpSeed) { uint256 timeJump = _bound(timeJumpSeed, 2 minutes, 40 days); - timestampStore.increaseCurrentTimestamp(timeJump); - vm.warp(timestampStore.currentTimestamp()); + vm.warp(block.timestamp + timeJump); _; } diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/invariant/handlers/LockupDynamicCreateHandler.sol index d918403f0..02f39c2ac 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/invariant/handlers/LockupDynamicCreateHandler.sol @@ -7,7 +7,6 @@ import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic. import { LockupDynamic } from "src/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; /// @dev This contract is a complement of {LockupDynamicHandler}. The goal is to bias the invariant calls @@ -25,14 +24,7 @@ contract LockupDynamicCreateHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor( - IERC20 asset_, - TimestampStore timestampStore_, - LockupStore lockupStore_, - ISablierV2LockupDynamic lockupDynamic_ - ) - BaseHandler(asset_, timestampStore_) - { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2LockupDynamic lockupDynamic_) BaseHandler(asset_) { lockupStore = lockupStore_; lockupDynamic = lockupDynamic_; } diff --git a/test/invariant/handlers/LockupDynamicHandler.sol b/test/invariant/handlers/LockupDynamicHandler.sol index 29ec97aa8..34bbf0a4e 100644 --- a/test/invariant/handlers/LockupDynamicHandler.sol +++ b/test/invariant/handlers/LockupDynamicHandler.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; /// @dev This contract and not {SablierV2LockupDynamic} is exposed to Foundry for invariant testing. The goal is @@ -14,10 +13,9 @@ import { LockupHandler } from "./LockupHandler.sol"; contract LockupDynamicHandler is LockupHandler { constructor( IERC20 asset_, - TimestampStore timestampStore_, LockupStore lockupStore_, ISablierV2LockupDynamic lockupDynamic_ ) - LockupHandler(asset_, timestampStore_, lockupStore_, lockupDynamic_) + LockupHandler(asset_, lockupStore_, lockupDynamic_) { } } diff --git a/test/invariant/handlers/LockupHandler.sol b/test/invariant/handlers/LockupHandler.sol index dcb145f3c..5637bd7a5 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/invariant/handlers/LockupHandler.sol @@ -7,7 +7,6 @@ import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { Lockup } from "src/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; /// @dev Common handler logic between {LockupLinearHandler} and {LockupDynamicHandler}. @@ -31,14 +30,7 @@ abstract contract LockupHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor( - IERC20 asset_, - TimestampStore timestampStore_, - LockupStore lockupStore_, - ISablierV2Lockup lockup_ - ) - BaseHandler(asset_, timestampStore_) - { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2Lockup lockup_) BaseHandler(asset_) { lockupStore = lockupStore_; lockup = lockup_; } diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/invariant/handlers/LockupLinearCreateHandler.sol index 1d69be7bf..fce35e868 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/invariant/handlers/LockupLinearCreateHandler.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; import { LockupLinear } from "src/types/DataTypes.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; @@ -25,14 +24,7 @@ contract LockupLinearCreateHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor( - IERC20 asset_, - TimestampStore timestampStore_, - LockupStore lockupStore_, - ISablierV2LockupLinear lockupLinear_ - ) - BaseHandler(asset_, timestampStore_) - { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2LockupLinear lockupLinear_) BaseHandler(asset_) { lockupStore = lockupStore_; lockupLinear = lockupLinear_; } diff --git a/test/invariant/handlers/LockupLinearHandler.sol b/test/invariant/handlers/LockupLinearHandler.sol index f27fafccd..9e2451660 100644 --- a/test/invariant/handlers/LockupLinearHandler.sol +++ b/test/invariant/handlers/LockupLinearHandler.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; /// @dev This contract and not {SablierV2LockupLinear} is exposed to Foundry for invariant testing. The goal is @@ -14,10 +13,9 @@ import { LockupHandler } from "./LockupHandler.sol"; contract LockupLinearHandler is LockupHandler { constructor( IERC20 asset_, - TimestampStore timestampStore_, LockupStore lockupStore_, ISablierV2LockupLinear lockupLinear_ ) - LockupHandler(asset_, timestampStore_, lockupStore_, lockupLinear_) + LockupHandler(asset_, lockupStore_, lockupLinear_) { } } diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/invariant/handlers/LockupTranchedCreateHandler.sol index 8a292be82..f4de81f15 100644 --- a/test/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/invariant/handlers/LockupTranchedCreateHandler.sol @@ -7,7 +7,6 @@ import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranche import { LockupTranched } from "src/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; /// @dev This contract is a complement of {LockupTranchedHandler}. The goal is to bias the invariant calls @@ -27,11 +26,10 @@ contract LockupTranchedCreateHandler is BaseHandler { constructor( IERC20 asset_, - TimestampStore timestampStore_, LockupStore lockupStore_, ISablierV2LockupTranched lockupTranched_ ) - BaseHandler(asset_, timestampStore_) + BaseHandler(asset_) { lockupStore = lockupStore_; lockupTranched = lockupTranched_; diff --git a/test/invariant/handlers/LockupTranchedHandler.sol b/test/invariant/handlers/LockupTranchedHandler.sol index 9194168e6..25ec40b98 100644 --- a/test/invariant/handlers/LockupTranchedHandler.sol +++ b/test/invariant/handlers/LockupTranchedHandler.sol @@ -6,7 +6,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; import { LockupStore } from "../stores/LockupStore.sol"; -import { TimestampStore } from "../stores/TimestampStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; /// @dev This contract and not {SablierV2LockupTranched} is exposed to Foundry for invariant testing. The goal is @@ -14,10 +13,9 @@ import { LockupHandler } from "./LockupHandler.sol"; contract LockupTranchedHandler is LockupHandler { constructor( IERC20 asset_, - TimestampStore timestampStore_, LockupStore lockupStore_, ISablierV2LockupTranched lockupTranched_ ) - LockupHandler(asset_, timestampStore_, lockupStore_, lockupTranched_) + LockupHandler(asset_, lockupStore_, lockupTranched_) { } } diff --git a/test/invariant/stores/TimestampStore.sol b/test/invariant/stores/TimestampStore.sol deleted file mode 100644 index 573b039d7..000000000 --- a/test/invariant/stores/TimestampStore.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -/// @dev Because Foundry does not commit the state changes between invariant runs, we need to -/// save the current timestamp in a contract with persistent storage. -contract TimestampStore { - uint256 public currentTimestamp; - - constructor() { - currentTimestamp = block.timestamp; - } - - function increaseCurrentTimestamp(uint256 timeJump) external { - currentTimestamp += timeJump; - } -} From 2a3fe7001754ffa7de20dc5199924b0b2c1b767e Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Sun, 2 Jun 2024 10:11:35 +0100 Subject: [PATCH 107/132] docs: update security assumptions --- SECURITY.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 0069de713..45fc4d2d8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -31,8 +31,8 @@ The Program does NOT cover the following: Vulnerabilities contingent upon the occurrence of any of the following also are outside the scope of this Program: -- Front-end bugs -- DDOS attacks +- Front-end bugs (clickjacking etc.) +- DDoS attacks - Spamming - Phishing - Social engineering attacks @@ -47,13 +47,14 @@ vulnerability, it must adhere to these assumptions as well: - The immutable variables `MAX_SEGMENT_COUNT` and `MAX_TRANCHE_COUNT` have values that cannot lead to an overflow of the block gas limit. -- The total supply of any ERC-20 token remains below 2128 - 1, i.e. `type(uint128).max`. +- The total supply of any ERC-20 token remains below 2128 - 1, i.e., `type(uint128).max`. - The `transfer` and `transferFrom` methods of any ERC-20 token strictly reduce the sender's balance by the transfer amount and increase the recipient's balance by the same amount. In other words, tokens that charge fees on transfers 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). +- There is no need for exponents greater than ~18.44 in `LockupDynamic` segments. ### Rewards From 8a3121013e2b199dcbac0a83db1c079843f012c3 Mon Sep 17 00:00:00 2001 From: maxdesalle Date: Wed, 5 Jun 2024 15:34:11 -0400 Subject: [PATCH 108/132] feat: add required file for OP retrofunding --- funding.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 funding.json diff --git a/funding.json b/funding.json new file mode 100644 index 000000000..c47fccfee --- /dev/null +++ b/funding.json @@ -0,0 +1,5 @@ +{ + "opRetro": { + "projectId": "0x7262ed9c020b3b41ac7ba405aab4ff37575f8b6f975ebed2e65554a08419f8f4" + } +} From 60a8e60d328b5987121e69b3ed1adaf01d3806ac Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 10 Jun 2024 12:07:13 +0100 Subject: [PATCH 109/132] perf: emit events before hook calls (#940) * perf: emit events before hook calls * refactor: remove updateMetadata modifier * test(refactor): reverse order of expected events emitted by transferFrom * test(refactor): reverse order of expected events emitted by transferFrom * refactor: Emit --- src/abstracts/SablierV2Lockup.sol | 42 ++++++------------- .../lockup/transfer-from/transferFrom.t.sol | 4 +- .../withdrawMaxAndTransfer.t.sol | 4 +- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index c7b848101..7a98bd10b 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -69,12 +69,6 @@ abstract contract SablierV2Lockup is _; } - /// @dev Emits an ERC-4906 event to trigger an update of the NFT metadata. - modifier updateMetadata(uint256 streamId) { - _; - emit MetadataUpdate({ _tokenId: streamId }); - } - /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -281,7 +275,7 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - function renounce(uint256 streamId) external override noDelegateCall notNull(streamId) updateMetadata(streamId) { + function renounce(uint256 streamId) external override noDelegateCall notNull(streamId) { // Check: the stream is not cold. Lockup.Status status = _statusOf(streamId); if (status == Lockup.Status.DEPLETED) { @@ -303,6 +297,9 @@ abstract contract SablierV2Lockup is // Log the renouncement. emit ISablierV2Lockup.RenounceLockupStream(streamId); + // Emit an ERC-4906 event to trigger an update of the NFT metadata. + emit MetadataUpdate({ _tokenId: streamId }); + // Interaction: 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); @@ -329,17 +326,7 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - function withdraw( - uint256 streamId, - address to, - uint128 amount - ) - public - override - noDelegateCall - notNull(streamId) - updateMetadata(streamId) - { + function withdraw(uint256 streamId, address to, uint128 amount) public override noDelegateCall notNull(streamId) { // Check: the stream is not depleted. if (_streams[streamId].isDepleted) { revert Errors.SablierV2Lockup_StreamDepleted(streamId); @@ -376,6 +363,9 @@ abstract contract SablierV2Lockup is // Effects and Interactions: make the withdrawal. _withdraw(streamId, to, amount); + // Emit an ERC-4906 event to trigger an update of the NFT metadata. + emit MetadataUpdate({ _tokenId: streamId }); + // Interaction: 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. @@ -572,7 +562,7 @@ abstract contract SablierV2Lockup is // Log the cancellation. emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount); - // Emits an ERC-4906 event to trigger an update of the NFT metadata. + // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); // Interaction: if the recipient is a contract, try to invoke the cancel hook on the recipient without @@ -608,22 +598,16 @@ abstract contract SablierV2Lockup is /// @param auth Optional parameter. If the value is not zero, the overridden implementation will check that /// `auth` is either the recipient of the stream, or an approved third party. /// @return The original recipient of the `streamId` before the update. - function _update( - address to, - uint256 streamId, - address auth - ) - internal - override - updateMetadata(streamId) - returns (address) - { + function _update(address to, uint256 streamId, address auth) internal override returns (address) { address from = _ownerOf(streamId); if (from != address(0) && to != address(0) && !_streams[streamId].isTransferable) { revert Errors.SablierV2Lockup_NotTransferable(streamId); } + // Emit an ERC-4906 event to trigger an update of the NFT metadata. + emit MetadataUpdate({ _tokenId: streamId }); + return super._update(to, streamId, auth); } diff --git a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 7a13c870f..31987fd0d 100644 --- a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -29,9 +29,9 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient, to: users.alice, tokenId: streamId }); - vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); + vm.expectEmit({ emitter: address(lockup) }); + emit Transfer({ from: users.recipient, to: users.alice, tokenId: streamId }); // Transfer the NFT. lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: streamId }); diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 891b44457..d9ad43859 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -107,9 +107,9 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is asset: dai }); vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId }); - vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: defaultStreamId }); + vm.expectEmit({ emitter: address(lockup) }); + emit Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); From 0679a79d87989dc3e1815502c60907e1c98cc3d1 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:24:10 +0300 Subject: [PATCH 110/132] fix: check the start time in SablierV2LockupLinear._calculateStreamedAmount (#941) test: test streamedAmountOf when cliff time is zero and the stream is PENDING test: correct tree branches in streamedAmountOf --- src/SablierV2LockupLinear.sol | 7 ++--- .../streamed-amount-of/streamedAmountOf.t.sol | 27 +++++++++++++++++-- .../streamed-amount-of/streamedAmountOf.tree | 7 +++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index a9ca622f4..5d448b048 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -187,10 +187,12 @@ contract SablierV2LockupLinear is /// - $d$ is the deposited amount. /// - $c$ is the cliff amount. function _calculateStreamedAmount(uint256 streamId) internal view override returns (uint128) { - // If the cliff time is in the future, return zero. uint256 cliffTime = uint256(_cliffs[streamId]); + uint256 startTime = uint256(_streams[streamId].startTime); uint256 blockTimestamp = block.timestamp; - if (cliffTime > blockTimestamp) { + + // If the cliff time or the start time is in the future, return zero. + if (cliffTime > blockTimestamp || startTime > blockTimestamp) { return 0; } @@ -204,7 +206,6 @@ contract SablierV2LockupLinear is // because there is no mix of amounts with different decimals. unchecked { // Calculate how much time has passed since the stream started, and the stream's total duration. - uint256 startTime = uint256(_streams[streamId].startTime); UD60x18 elapsedTime = ud(blockTimestamp - startTime); UD60x18 totalDuration = ud(endTime - startTime); diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index a49582dcc..b1a94746d 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { LockupLinear } from "src/types/DataTypes.sol"; + import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; @@ -17,7 +19,28 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is StreamedAmountOf_Integration_Concrete_Test.setUp(); } - function test_StreamedAmountOf_CliffTimeInThePast() + modifier givenStatusPendind() { + _; + } + + function test_StreamedAmountOf_CliffTimeZero() + external + givenNotNull + givenStreamHasNotBeenCanceled + givenStatusPendind + { + vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); + + LockupLinear.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); + timestamps.cliff = 0; + uint256 streamId = createDefaultStreamWithTimestamps(timestamps); + + uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); + uint128 expectedStreamedAmount = 0; + assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); + } + + function test_StreamedAmountOf_CliffTimeInTheFuture() external view givenNotNull @@ -41,7 +64,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } - function test_StreamedAmountOf_CliffTimeInTheFuture() + function test_StreamedAmountOf_CliffTimeInThePast() external givenNotNull givenStreamHasNotBeenCanceled diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree index 4a8e35c69..e87b5df2f 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree @@ -1,8 +1,11 @@ streamedAmountOf.t.sol +├── given the stream's status is "PENDING" +│ └── given the cliff time is zero +│ └── it should return zero └── given the stream's status is "STREAMING" - ├── given the cliff time is in the past + ├── given the cliff time is in the future │ └── it should return zero ├── given the cliff time is in the present │ └── it should return the correct streamed amount - └── given the cliff time is in the future + └── given the cliff time is in the past └── it should return the correct streamed amount From 8c9972fc3a4fa817ff64b551b5256d855726ccb7 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 12 Jun 2024 00:43:27 +0300 Subject: [PATCH 111/132] docs: add dev natspec for statusOf function --- src/interfaces/ISablierV2Lockup.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 28c00f8ce..28183b65f 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -150,6 +150,7 @@ interface ISablierV2Lockup is function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount); /// @notice Retrieves the stream's status. + /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. function statusOf(uint256 streamId) external view returns (Lockup.Status status); From 5d73001bafd0a5e8336f7b9147f8f0fb047344c6 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 14 Jun 2024 12:20:04 +0100 Subject: [PATCH 112/132] build: bump deps --- bun.lockb | Bin 42760 -> 43089 bytes package.json | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lockb b/bun.lockb index d83cc08be782b9d93f7ed79e875adf2368669288..c7900ccb45dfcb6ae6b0c8eddd7490a173f6331d 100755 GIT binary patch delta 4138 zcmaJ^4^&iT7JuKsz&!rQU!h?@1r=?@abTQ=3FU#SNg$dQN~P$4Bq;wJW`RLr1_Uy* zQ+73Jv#?C`n3grW=~y0RQ;(*m9Iadn)9laYzhygHMy|TQ?>(No=j>_UnfdPf-Fv@# z?{~lZ{ducD(e$3yykNZl%8Mu7d9CXG<2!|ZzxX33i}HS$6w`Ha=vsM>W6CVMv%gdjoiIPJw1rBK*3h>vI#elutY-`rh=Sva>c#fjGC^nu9s=B}Q@oiVbS>a;PXI!gg(#M=b#4AndpaC zj}4RuoCBjA-%rnItPzKy%H3B$#Pi!jy_#6}K5)6Mm4jJb4$AQ?Oeoi$2FimCz=+}2 z^8;`KXsN?d?HFI$a0`5{e-3;u@6;>$t3kQ%DRGLOk}`Y6GQ@rym?x>sUOWD&3j5L} zd%)m>_^l!t0eKSSHaOr}918E8>Oe70&lXS~XxZQZe#6m{1=Q;oYf_8MHCzy2*keU6 z81~dwSJ)j6yNlDsEQ{EwzYNc7S|3Npq9YuewZTCYva+HRKW{@idmmqh+0@BDD8^{(ci5J0}qVV7_g?zyhE29ClZ<8%V zVo~HmJDq$XlIX@#n#X8Qphtk1Y&!wV>>(gO>KUF+zEDZr1;t|p(*GwpnEd5o_tY~cy*A+s3*!Qj>F>M!`4!E zm{n66MvY>o_&S)mU}~r**eYHH;v-QqGaYq4=pfR{BONM=_T>bpoWs&H1dJB0$T>J4aM6j zAU+ydLyU@1?Xy@b%OhW$B(4IFk4>qp9v~ha^nNry=>`g$*a$qQp zSnMgev_B$4YsXtL?GMRdACWI!5(BWS3>Hb0l}#mEf+W5H9`7qV(_R3YLX#6R#Jsrw z_RtQL1}zP-5G(sDxrRw%0ya&a8fC#1&;WQ_!BeIMwZJZuYq%tij=$$2)XMBM0NzpX zlsdwo#6)aD94Vu*1M$g6M3|hNKzyX|g6a4UC<7>nT4K`4l_-gi4pY(@NEo}g5s1g6 zSULs7qY=0z7D}!piRF?nNfHSg7+<`QU?MLA%?H8+VIn1Rjhx5YsdwaL5@C-xEK9`U7J=g;R2JG$V7b5&bv%t0HvpZjUU;-SWa?L+$3woaQ9zvxf(i@xq?_TEl; zVRTmVH=9%DesC`ZazBW=kT>(9XjNH+_SO!acxcgRr{s>$L7yDJiBSl zh`_9mehPa#&Tu1dXj^I&4LQ+9C+EcG`|s2iC9H}+a4>4#M%S5x?RD-C@2oquwSM(8 zeZQ~s_7~N8oXubEusr$ZOZ4rPy~o0}j}BB+2bgjee*fLbWzKb{vTz14;ZE2c&{|?C zv*=lIG#w0##o6JXh$E(~yvixuM4GY7c{HHvakCpe!o2oEH{+@lQlQh8VBZZz_Mhh* z@6LkV8g|~hpwR2baj4qy3}!PNTGMH@IM%y){-~kwH;Mx?6)X#8Wwr2v$K<3`M8K`w6z`i-&G@)j%%Ch~p61;J2`Ai=Qayn{;sMf4tA5+psV9 zXPK0`LeCziJhTe`47pe6E$V%|w{XYlhyU62t%fzH8dHrE1wp-w>yNGz``UNE1-oWQ zQU&1}orD#EzF(2g-XzOPGwY>tvz~1H}E3}Hk#b5H>h{xmRBxr{PA}eZb5EU=BJ33H|tq7 zJqs=6N-lU7MLs?H?H3!{pat{1REQ2hu3qV9q$GQ{Bqyc~$`Qa0%69A7UJ7;V4eAGh z`R0}R@38HG&@wB&6s^zbNoc8`1<_R@Y3A2|DTNk1DG@&pxq7Q#^@y0%@LE03JugEw z7R`_0bitj*Y!uKKHAiJpF#a*IIw)o7uVdm(NMD* z(=fwAC!K25vk~+|tC>xqgjIT`a58B&-uKWlw8yD^mD!?xV-_zTH90FdEFCsd5eZ!V zZW9U(UyAz{M(HM^C(k!}ZlT0By}Wv&X;zySo(kH`mfv0*>c>T! zbk>l2`sj3dxU!{dw7<<9l-t2~BHVF0uo*|wkoJ_IhC!BZ8%=F5VrjIcU828q8Dg?( z9K{nV?as0Z<7F~l-il~;*9e-@Q6kFg-{@S@NWEKQy@xxRhsR+1;*8?*stM}pU@Tcm fJzeoM`{`({y!FvT-6I2S)^vNx15eTN!p?sKbY2*7 delta 3891 zcmaJ@4^&iD8h>|iWbOb00>N`M1Wet6fnmTwNFKUsj5#JrX_kKm8G#xUXGZ?1FbHUq zWx;2qS?dWq+F5I}W;<;sTkX%LQ^$g`ldDN;x$U-Ud)itpEBANbo9FI1d)jyAzVH6N z?|a{$d%t_<8yYm+|Gwc7>#ugMYJA$dZs%p=$gBBNvbM*TY|MU7YC61NdArl|R?k2C zTlYxnM zfG7m^uC8_a>m_L$@F?KZCe51yp@_=2LQCjPU}3+pVO2vT41lPDSHMS9ox$9wLK=`T zv=vksI0-7!Zv#ye2EfEL=*BApv~G1kHS`g368f)#iti6c@pGW~1uudrjjBKjrX_0zbpCywwr1h+IQSwE1}awUFZj*^x&+^08mt5r z0WXA6flDZ4a3mjts&Ky!BC)=MG-OEcjDRa_ZHcaG5LDo$*ifNe4Jv|7L&k6yybL@J z)Z_E5_T_n6&9bKdCHO+V7g*>&4k~iO$ybxt=nmA|rWDzxdWxlIz#l`?t1bN| z6Z<1MO-e!%3{HV6N?kHiGQUZP-lvF3F^n{jnU}K}*T~cn?iWsNs)MkZ^fybr+sg7@K1r}12NTFE`<^l)=7~Bg&)A_D}`jF>h)hh zYIZ8h#fcL#H9oeIBBK=kBzQByi&ZV1CugF zh^oP}uhZ=(r#skUii}ZsKX@W7wW9bSkcbW_&S5a8(*u@rz6J+RFtvi-2PD>692$pl zBCeY`bTqll*o0XP9gQzzA5vtj!qafEL`x&Z!4{BnoWfrOPkgI7GhP6iL9TISeDRq7 z_OK185LyOGj(4!XQs{ccn2UR}MAQVUC7!A9-vevAfl6TCPzb!DvAXrXgc9Q875)i0 zqF%6PsDc9AKmuubGy#bnXX>`R1|)J+Yl43VR0d=gGFCvLEQQxxuPtS)$eZs05?iI& z8U_;4NUHu=3S}$oE{bF;d;s^CIIxgl6Tbnv2MDErO`J!eoP}%~oynP${M>l05TxkS zMQ_ATQt!00klKmrvdv)1T|5d#b0?^SMnG zyTb`?>-=(7`uOJ`Wqfhy_QCM(*|$D*Y4D|=*MB8nsBBt#{IL%czMuT3%N0|P{Q1G* zQSEP^Zs{0}$X z_}~}qZ#BeBUK+f+v_1#l*zj&JR7Nn~ojbEbl zn?}(1YE#-s+`J+o0}^WTc>;k3kMCf3TJ^(>`NBun_cqaJC>MuvF;Q9Hg_K0}{23$xP)a6g>3kNBSx znj!sHU6R&@F#MShe&Wl*xej!FyG&zN&nG9zShR^h1h$P zo&N6^cc6gAEV#PM#0snhR$Jjzy4q?r7GYjMg>89eQ#-!S!dlO!hPGLJ3F5#_81&LB zZFcK(iX~WuS0omZnv`mdJXS=^flfuQ_eaU z3(%T%GV7)->tu`GU;gA}`VS^pAIeh?V$79UFQs}!)CQv zaV6@#seGi5pX%Me4|eU4z~dD<1uKbkX}ybuY1RfiJ56nP=hE{VWTw#J4KDmIrFFP0 zdOv#G^Fu8cK9P%Iy-2caCW_FtI>3=$7DbFA3{kS6V*rnE%I0b#34W{~6@!lr4I%*tPTY(1Lj@ZqWhy0CK&>otrx`ynA9+VN{L) zUZtv_%nsAIpls0_Wc#JB?sDbTMQ@7hietqk&Udf%-af Date: Fri, 14 Jun 2024 15:48:54 +0300 Subject: [PATCH 113/132] Build/npm ignore file (#936) * build: add npm ignore file build: exclude *.t.sol files from NPM package * test: absolute paths in precompiles test * build: remove .npmignore build: add "!test/utils/*.t.sol" in package json files * build: npm ignore file in test utils --------- Co-authored-by: Paul Razvan Berg --- test/utils/.npmignore | 1 + test/utils/Precompiles.t.sol | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 test/utils/.npmignore diff --git a/test/utils/.npmignore b/test/utils/.npmignore new file mode 100644 index 000000000..c607d373a --- /dev/null +++ b/test/utils/.npmignore @@ -0,0 +1 @@ +*.t.sol diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 50b1037ee..5dcd11e88 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -3,11 +3,11 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { Precompiles } from "../../precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { Precompiles } from "precompiles/Precompiles.sol"; +import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; From c152133e91c3ecab9971c07f93482ea5f9a27ad5 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 14 Jun 2024 19:48:15 +0100 Subject: [PATCH 114/132] build: bump solc to v0.8.26 (#944) * build: bump solc * build: update precompiles --------- Co-authored-by: Paul Razvan Berg --- .github/workflows/multibuild.yml | 2 +- foundry.toml | 2 +- precompiles/Precompiles.sol | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/multibuild.yml b/.github/workflows/multibuild.yml index ddfcbefdf..bd42ec6f0 100644 --- a/.github/workflows/multibuild.yml +++ b/.github/workflows/multibuild.yml @@ -22,5 +22,5 @@ jobs: uses: "PaulRBerg/foundry-multibuild@v1" with: min: "0.8.22" - max: "0.8.23" + max: "0.8.26" skip-test: "true" diff --git a/foundry.toml b/foundry.toml index 4a8289e4a..547b35381 100644 --- a/foundry.toml +++ b/foundry.toml @@ -18,7 +18,7 @@ out = "out" script = "script" sender = "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38" - solc = "0.8.23" + solc = "0.8.26" src = "src" test = "test" diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index ed7adf5a6..9f56f79c4 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,13 +26,13 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c034620003c3576001600160401b0390601f601f196200584d3881900383810183168501919086831186841017620002e557808692606094604052833981010312620003c35782516001600160a01b038082169590929091869003620003c35760209485810151938416809403620003c357604001519362000081620003c7565b95601d87527f5361626c696572205632204c6f636b75702044796e616d6963204e465400000081880152620000b5620003c7565b90601182527029a0a116ab1916a627a1a5aaa816a22ca760791b81830152306080528751858111620002e5576001988954908a82811c92168015620003b8575b84831014620002c657818684931162000365575b50839086831160011462000305575f92620002f9575b50505f19600383901b1c191690891b1788555b8151948511620002e557600254938885811c95168015620002da575b82861014620002c65784848796116200026c575b5081938511600114620002065750505f92620001fa575b50505f19600383901b1c191690841b176002555b60018060a01b031984815f5416175f556008541617600855604051925f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526007556154659081620003e8823960805181613830015260a051818181610bb901526138f70152f35b015190505f8062000179565b8895939291931660025f52835f20935f905b82821062000252575050841162000239575b505050811b016002556200018d565b01515f1960f88460031b161c191690555f80806200022a565b8484015186558a9790950194938401939081019062000218565b90919293945060025f52825f208580880160051c820192858910620002bc575b9188978c9297969594930160051c01915b828110620002ad57505062000162565b5f81558897508b91016200029d565b925081926200028c565b634e487b7160e01b5f52602260045260245ffd5b94607f16946200014e565b634e487b7160e01b5f52604160045260245ffd5b015190505f806200011f565b90878c941691845f52855f20925f5b878282106200034e575050841162000335575b505050811b01885562000132565b01515f1960f88460031b161c191690555f808062000327565b8385015186558f9790950194938401930162000314565b9091508a5f52835f208680850160051c820192868610620003ae575b918d91869594930160051c01915b8281106200039f57505062000109565b5f81558594508d91016200038f565b9250819262000381565b91607f1691620000f5565b5f80fd5b60408051919082016001600160401b03811183821017620002e55760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146125b257508063027b67441461259057806306fdde03146124cf578063081812fc146124b1578063095ea7b3146123b85780631400ecec146123185780631c1cdd4c146122b45780631e99d5691461229757806323b872dd1461228057806331df3d481461217457806340e58ee514611eca578063425d30dd14611e7a57806342842e0e14611e4157806342966c6814611c7b5780634426757014611c555780634857501f14611be45780634869e12d14611baa5780634cc55e1114611ab257806354c022921461182f57806357404b121461179a5780636352211e1461176b5780636d0cee751461176b57806370a08231146116fd57806375829def1461166e5780637cad6cd1146115775780637de6b1db1461136a5780638659c27014611024578063894e9a0d14610cab5780638f69b99314610c2b5780639067b67714610bdc5780639188ec8414610ba257806395d89b4114610a99578063a22cb465146109e0578063a80fc0711461098f578063ad35efd414610930578063b2564569146108e0578063b637b86514610887578063b88d4fde146107ff578063b8a3be66146107ca578063b971302a1461077c578063bc2be1be1461072d578063c156a11d146105ee578063c87b56dd146104dd578063d4dbd20b1461048c578063d511609f14610441578063d975dfed146103f6578063e985e9c5146103a3578063ea5ead1914610375578063eac8f5b814610324578063f590c176146102c3578063f851a4401461029e5763fdd46d6014610258575f80fd5b3461029a57606036600319011261029a576102716126dd565b6044356001600160801b038116810361029a5761029891610290613826565b600435613247565b005b5f80fd5b3461029a575f36600319011261029a5760206001600160a01b035f5416604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060405f205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160a01b03600160405f20015416604051908152f35b3461029a57604036600319011261029a576102986004356103946126dd565b61039d826140b8565b91612ea8565b3461029a57604036600319011261029a576103bc6126c7565b6103c46126dd565b906001600160a01b038091165f52600660205260405f2091165f52602052602060ff60405f2054166040519015158152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576104306020916140b8565b6001600160801b0360405191168152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f5260096020526020600260405f20015460801c604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160801b03600360405f20015416604051908152f35b3461029a5760208060031936011261029a57600435906104fc826135d7565b505f6001600160a01b0360085416926044604051809581937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9182156105e3575f9261056b575b506105676040519282849384528301906126a2565b0390f35b9091503d805f833e61057d8183612863565b810190828183031261029a5780519067ffffffffffffffff821161029a570181601f8201121561029a5780516105b281612885565b926105c06040519485612863565b81845284828401011161029a576105dc91848085019101612681565b9082610552565b6040513d5f823e3d90fd5b3461029a57604036600319011261029a5760043561060a6126dd565b610612613826565b815f52600960205260ff600160405f20015460a81c161561071657815f5260036020526001600160a01b038060405f205416918233036106f757610655846140b8565b6001600160801b0381166106e6575b50818116156106cf5783610677916136eb565b908116806106975760248460405190637e27328960e01b82526004820152fd5b820361069f57005b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6024604051633250574960e11b81525f6004820152fd5b6106f1908486612ea8565b84610664565b60405163216caf0d60e01b815260048101859052336024820152604490fd5b6024826040519062b8e7e760e51b82526004820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602064ffffffffff60405f205460a01c16604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160a01b0360405f205416604051908152f35b3461029a57602036600319011261029a576004355f526009602052602060ff600160405f20015460a81c166040519015158152f35b3461029a57608036600319011261029a576108186126c7565b6108206126dd565b6064359167ffffffffffffffff831161029a573660238401121561029a5782600401359161084d83612885565b9261085b6040519485612863565b808452366024828701011161029a576020815f9260246102989801838801378501015260443591612d41565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600a6020526105676108cc60405f20612cb4565b60405191829160208352602083019061276d565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060ff600160405f20015460b01c166040519015158152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576109689061366b565b604051600582101561097b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f52600960205260206001600160801b03600260405f20015416604051908152f35b3461029a57604036600319011261029a576109f96126c7565b6024359081151580920361029a576001600160a01b0316908115610a6857335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029a575f36600319011261029a576040515f6002549060018260011c9160018416918215610b98575b6020948585108414610b845785879486865291825f14610b64575050600114610b09575b50610af592500383612863565b6105676040519282849384528301906126a2565b84915060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace905f915b858310610b4c575050610af5935082010185610ae8565b80548389018501528794508693909201918101610b35565b60ff191685820152610af595151560051b8501019250879150610ae89050565b634e487b7160e01b5f52602260045260245ffd5b92607f1692610ac4565b3461029a575f36600319011261029a5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602064ffffffffff60405f205460c81c16604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d57610c639061366b565b60058110158061097b5760028214908115610c9f575b8115610c8d575b6020826040519015158152f35b905061097b5760046020911482610c80565b5050600381145f610c79565b3461029a57602036600319011261029a57604051610180810181811067ffffffffffffffff821117610fed57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d23612c62565b61014082015201526004355f52600960205260ff600160405f20015460a81c161561100c576004355f52600960205260405f20610df0600260405192610d6884612846565b80546001600160a01b038116855264ffffffffff8160a01c16602086015264ffffffffff8160c81c16604086015260ff8160f01c161515606086015260f81c1515608085015260ff60018201546001600160a01b03811660a0870152818160a01c16151560c0870152818160a81c16151560e087015260b01c16151561010085015201612c80565b610120820152610e0160043561366b565b600581101561097b57600214611001575b610120810151906001600160a01b0360a0820151169164ffffffffff604083015116606083015115159160c0840151151560e085015115156101008601511515916004355f5260036020526001600160a01b0360405f20541697600a60205260405f20956001600160a01b0389511697608064ffffffffff60208c0151169a01511515916040519a8b67ffffffffffffffff610180828181011092011117610fed576101609c610f009b6101808e016040528d5260208d015260408c015260608b015260808a015260a089015260c088015260e0870152610100860152610120850152610140840152612cb4565b82820152610567604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061276d565b634e487b7160e01b5f52604160045260245ffd5b5f6060820152610e12565b602460405162b8e7e760e51b81526004356004820152fd5b3461029a5760208060031936011261029a5760043567ffffffffffffffff811161029a5761105690369060040161273c565b9061105f613826565b5f915b80831061106b57005b611076838284612c09565b3592611080613826565b835f52600980865260ff6001818160405f20015460a81c161561135357865f5282885260405f20828282015460a01c165f146110ce5760248860405190634a5541ef60e01b82526004820152fd5b969495965460f81c61133b576110f8855f5260096020526001600160a01b0360405f205416331490565b1561131c57611106856135f8565b92855f5280895261111c600260405f2001612c80565b936001600160801b039384865116858316101561130457875f52828b5260405f205460f01c16156112ec5780848b8161115f94818a5116031697015116906128d7565b865f52818a528960405f207f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50878a61123c845499600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8c161786558716998a156112d3575b6003809601846fffffffffffffffffffffffffffffffff198254161790556001600160a01b03809116998a9688528160405f205416998a985260405f200154169661121284878a6144cd565b60405193849384916040919493606084019584526001600160801b03809216602085015216910152565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce789604051888152a1803b61127f575b5050505060019150019190611062565b803b1561029a576001955f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16112c4575b80808061126f565b6112cd90612832565b856112bc565b898601600160a01b60ff60a01b198254161790556111c6565b602487604051906339c6dc7360e21b82526004820152fd5b602488604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b815260048101869052336024820152604490fd5b6024856040519063fe19f19f60e01b82526004820152fd5b6024876040519062b8e7e760e51b82526004820152fd5b3461029a5760208060031936011261029a5760043590611388613826565b815f526009815260ff600160405f20015460a81c1615610716576113ab8261366b565b600581101561097b57600481036113d45760248360405190634a5541ef60e01b82526004820152fd5b600381036113f4576024836040519063fe19f19f60e01b82526004820152fd5b60021461155f57611419825f5260096020526001600160a01b0360405f205416331490565b1561154057815f526009815260ff60405f205460f01c161561152857815f526009815260405f2060ff60f01b19815416905560405191807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a2600382526001600160a01b0360405f20541692833b6114ba575b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78383604051908152a1005b833b1561029a575f81602481837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7987f450154640000000000000000000000000000000000000000000000000000000083528760048401525af11561148e5761152290612832565b8361148e565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b3461029a57602036600319011261029a576004356001600160a01b039081811680910361029a57815f5416338103611645575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116315760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b3461029a57602036600319011261029a576116876126c7565b5f546001600160a01b03808216923384036116d6576001600160a01b031993501691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b6040516331b339a960e21b81526001600160a01b0385166004820152336024820152604490fd5b3461029a57602036600319011261029a576001600160a01b0361171e6126c7565b16801561173b575f526004602052602060405f2054604051908152f35b60246040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152fd5b3461029a57602036600319011261029a5760206117896004356135d7565b6001600160a01b0360405191168152f35b3461029a57602036600319011261029a576004355f60206040516117bd81612816565b8281520152805f52600960205260ff600160405f20015460a81c161561030d575f5260096020526040805f205464ffffffffff8251916117fc83612816565b818160a01c16835260c81c16602082015261182d825180926020908164ffffffffff91828151168552015116910152565bf35b3461029a576020600319818136011261029a5760043567ffffffffffffffff9182821161029a576101208236039182011261029a5761186c613826565b60c4820135906022190181121561029a57810160048101359083821161029a57602401606082023603811361029a576118a6913691612b3a565b918251916118b383612b22565b926118c16040519485612863565b808452601f196118d082612b22565b01865f5b828110611a9c5750505064ffffffffff90814216936001600160801b0396876118fc82613882565b515116828a61190a84613882565b510151168580604061191b86613882565b510151168901169060405192611930846127fa565b83528b830152604082015261194488613882565b5261194e87613882565b506001938760015b8a8c878310611a1c5790838b8b61196f81600401612c41565b9261197c60248301612c41565b9261198960448401612c2d565b946064840135946001600160a01b039586811680910361029a57611a14986119d498611a09986119bb60848a01612c55565b94816119c960a48c01612c55565b976040519d8e6127dd565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612bda565b6101008201526138a3565b604051908152f35b889385806040611a4f8b86611a408a8e9a611a37828d61388f565b5151169a61388f565b51015116945f1989019061388f565b51015116816040611a60888c61388f565b5101511601169160405193611a74856127fa565b84528301526040820152611a88828c61388f565b52611a93818b61388f565b50018890611956565b611aa4612c62565b8282890101520187906118d4565b3461029a57604036600319011261029a5767ffffffffffffffff60043581811161029a57611ae490369060040161273c565b9160243590811161029a57611afd90369060040161273c565b9091611b07613826565b818403611b73575f5b848110611b1957005b80611b6d611b2a6001938886612c09565b35611b36838987612c09565b355f5260036020526001600160a01b0360405f205416611b5f611b5a85898b612c09565b612c2d565b91611b68613826565b613247565b01611b10565b60448483604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d57610430602091614013565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f611c1d8261366b565b600581101561097b57600203611c3b575b6020906040519015158152f35b505f526009602052602060ff60405f205460f01c16611c2e565b3461029a575f36600319011261029a5760206001600160a01b0360085416604051908152f35b3461029a5760208060031936011261029a5760043590611c99613826565b815f526009815260ff600160405f20015460a81c161561071657815f526009815260ff600160405f20015460a01c1615611e1057611cd682613fae565b1561154057815f52600381526001600160a01b038060405f205416151580611e09575b80611df0575b611dd8577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f205416918215928315611da2575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1611d8a57005b60249060405190637e27328960e01b82526004820152fd5b611dc1855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f198154019055611d3d565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c1615611cff565b505f611cf9565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b3461029a57611e4f36612707565b60405191602083019383851067ffffffffffffffff861117610fed57610298946040525f8452612d41565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d575f526009602052602060ff600160405f20015460a01c166040519015158152f35b3461029a5760208060031936011261029a5760043590611ee8613826565b815f52600980825260ff600160405f20015460a81c161561215d57825f5280825260405f2060ff600182015460a01c165f14611f365760248460405190634a5541ef60e01b82526004820152fd5b5460f81c61214557611f5c835f5260096020526001600160a01b0360405f205416331490565b1561212657611f6a836135f8565b835f52818352611f7f600260405f2001612c80565b936001600160801b039182865116838216101561155f57815f5283855260ff60405f205460f01c161561152857611fe5818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906128d7565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8816178955821697881561210c575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f20015416936120968c84876144cd565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b6120c857005b813b1561029a575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161210357005b61029890612832565b60018101600160a01b60ff60a01b19825416179055612029565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461029a5760031960203682011261029a5760043567ffffffffffffffff9182821161029a5761014090823603011261029a576121af613826565b604051916121bc836127dd565b6121c8826004016126f3565b83526121d6602483016126f3565b60208401526121e7604483016128a1565b604084015260648201356001600160a01b038116810361029a576060840152612212608483016127d0565b608084015261222360a483016127d0565b60a084015261223460c48301612b10565b60c084015260e482013590811161029a578101913660238401121561029a57611a09611a14926122706020953690602460048201359101612b3a565b60e0840152610104369101612bda565b3461029a5761029861229136612707565b916128f0565b3461029a575f36600319011261029a576020600754604051908152f35b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576122ec9061366b565b600581101561097b57806020911590811561230d575b506040519015158152f35b600191501482612302565b3461029a57602036600319011261029a57600435805f52600960205260ff600160405f20015460a81c161561030d576020905f90805f526009835260405f2060ff815460f01c16806123a6575b61237d575b50506001600160801b0360405191168152f35b61239f92506001600160801b03600261239992015416916135f8565b906128d7565b828061236a565b5060ff600182015460a01c1615612365565b3461029a57604036600319011261029a576123d16126c7565b6024356123dd816135d7565b3315158061249e575b80612474575b6124445781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f205416156123ec565b50336001600160a01b03821614156123e6565b3461029a57602036600319011261029a5760206117896004356128b5565b3461029a575f36600319011261029a576040515f600190600154918260011c9160018416918215612586575b6020948585108414610b845785879486865291825f14610b6457505060011461252b5750610af592500383612863565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b85831061256e575050610af5935082010185610ae8565b80548389018501528794508693909201918101612557565b92607f16926124fb565b3461029a575f36600319011261029a57602060405167016345785d8a00008152f35b3461029a57602036600319011261029a57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361029a57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612657575b811561262d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612626565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061261f565b5f5b8381106126925750505f910152565b8181015183820152602001612683565b906020916126bb81518092818552858086019101612681565b601f01601f1916010190565b600435906001600160a01b038216820361029a57565b602435906001600160a01b038216820361029a57565b35906001600160a01b038216820361029a57565b606090600319011261029a576001600160a01b0390600435828116810361029a5791602435908116810361029a579060443590565b9181601f8401121561029a5782359167ffffffffffffffff831161029a576020808501948460051b01011161029a57565b9081518082526020808093019301915f5b82811061278c575050505090565b835180516001600160801b031686528083015167ffffffffffffffff168684015260409081015164ffffffffff16908601526060909401939281019260010161277e565b3590811515820361029a57565b610120810190811067ffffffffffffffff821117610fed57604052565b6060810190811067ffffffffffffffff821117610fed57604052565b6040810190811067ffffffffffffffff821117610fed57604052565b67ffffffffffffffff8111610fed57604052565b610140810190811067ffffffffffffffff821117610fed57604052565b90601f8019910116810190811067ffffffffffffffff821117610fed57604052565b67ffffffffffffffff8111610fed57601f01601f191660200190565b35906001600160801b038216820361029a57565b6128be816135d7565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b03918216908216039190821161163157565b906001600160a01b038091169081156106cf57835f526020906003825260409181835f205416151580612b08575b80612af0575b612ad957855f526003815281835f2054169333151580612a32575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856129fd575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036129cf5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b612a1c885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f198154019055612969565b80612a98575b15612a43575f61293f565b838786612a60576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503385148015612abd575b80612a385750865f52600582523383855f20541614612a38565b50845f5260068252835f20335f52825260ff845f205416612aa3565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c1615612924565b50600161291e565b359064ffffffffff8216820361029a57565b67ffffffffffffffff8111610fed5760051b60200190565b929192612b4682612b22565b604094612b566040519283612863565b8195848352602080930191606080960285019481861161029a57925b858410612b825750505050505050565b868483031261029a57825190612b97826127fa565b612ba0856128a1565b8252858501359067ffffffffffffffff8216820361029a57828792838b950152612bcb868801612b10565b86820152815201930192612b72565b919082604091031261029a57604051612bf281612816565b6020808294612c00816126f3565b84520135910152565b9190811015612c195760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361029a5790565b356001600160a01b038116810361029a5790565b35801515810361029a5790565b60405190612c6f826127fa565b5f6040838281528260208201520152565b90604051612c8d816127fa565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b908154612cc081612b22565b92604093612cd16040519182612863565b82815280946020809201925f5260205f20905f935b858510612cf557505050505050565b60018481928451612d05816127fa565b64ffffffffff87546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1686820152815201930194019391612ce6565b91929092612d508185856128f0565b833b612d5d575b50505050565b6020906001600160a01b0380951694612dbe60405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906126a2565b03815f875af15f9181612e4b575b50612e025782612dda614089565b8051919082612dfb5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603612e3357505f808080612d57565b60249060405190633250574960e11b82526004820152fd5b9091506020813d602011612ea0575b81612e6760209383612863565b8101031261029a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361029a57905f612dcc565b3d9150612e5a565b612eb0613826565b805f5260099160209280845260409160ff6001845f20015460a81c161561323157835f5281855260ff6001845f20015460a01c1661321a576001600160a01b03808216928315613203576001600160801b03938489169182156131ec57875f526003895283875f2054169384831415806131dc575b6131b957612f32896140b8565b8781168511613188575090898992835f52828252895f20988d828b54169a6002015460801c90612f61916140de565b855f528484528b5f20600201908282549160801b6fffffffffffffffffffffffffffffffff19169116178155612f9690612c80565b9080848301511691818d8183511692015116612fb1916128d7565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d9361315a575b845f52825260018a5f2001541694612ff58189886144cd565b8951908152a48033141580613150575b6130ef575b8233141590816130e4575b816130d9575b5061304d575b50507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7935051908152a1565b813b1561029a578251636fd110e960e01b8152600481018590523360248201526001600160a01b0390911660448201526001600160801b0390951660648601527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794905f9082908183816084810103925af16130ca575b80613021565b6130d390612832565b5f6130c4565b90508214155f61301b565b833b15159150613015565b803b1561029a578351636fd110e960e01b8152600481018690523360248201526001600160a01b03831660448201526001600160801b03881660648201525f8160848183865af1613141575b5061300a565b61314a90612832565b5f61313b565b50803b1515613005565b845f528083528a5f2060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055612fdc565b885163287ecaef60e21b8152600481018b90526001600160801b038d81166024830152919091166044820152606490fd5b606489848a519163b34359d360e01b835260048301523360248301526044820152fd5b506131e689613fae565b15612f25565b60248888519063d2aabcd960e01b82526004820152fd5b602486865190630ff7ee2d60e31b82526004820152fd5b602484845190634a5541ef60e01b82526004820152fd5b60248484519062b8e7e760e51b82526004820152fd5b929192805f5260099360209285845260409160ff6001845f20015460a81c1615613231575f96845f5280865260ff6001855f20015460a01c166135c0576001600160a01b038084169182156135a9576001600160801b039283851691821561359257885f5260038a5283885f205416938483141580613582575b61355f576132e76132d18b614013565b8b5f52838d5260028b5f20015460801c906128d7565b868116851161352e5750908a8a92835f528282528a805f20988a838b54169a6002015460801c90613317916140de565b865f52858552825f20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561334c90612c80565b81808683015116938183511692015116613365916128d7565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93613500575b845f52825260018b5f20015416946133a9818b886144cd565b8a51908152a480331415806134f6575b613491575b813314159081613486575b8161347b575b50613403575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793945051908152a1565b908188923b15613477578451636fd110e960e01b8152600481018790523360248201526001600160a01b0390941660448501526001600160801b03909116606484015282908183816084810103925af161345f575b80806133d5565b6134698691612832565b6134735784613458565b8480fd5b8280fd5b90508114155f6133cf565b823b151591506133c9565b803b1561029a578451636fd110e960e01b8152600481018790523360248201526001600160a01b03851660448201526001600160801b03841660648201525f8160848183865af16134e3575b506133be565b6134ee919950612832565b5f975f6134dd565b50803b15156133b9565b845f528083528b5f2060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055613390565b895163287ecaef60e21b8152600481018c90526001600160801b038981166024830152919091166044820152606490fd5b60648a848b519163b34359d360e01b835260048301523360248301526044820152fd5b5061358c8a613fae565b156132c1565b60248989519063d2aabcd960e01b82526004820152fd5b602487875190630ff7ee2d60e31b82526004820152fd5b602485855190634a5541ef60e01b82526004820152fd5b805f5260036020526001600160a01b0360405f205416908115611d8a575090565b64ffffffffff804216825f52600960205260405f2091825482828260a01c1610156136625760c81c1611156136505750600a602052600160405f2054115f1461364757613644906141b1565b90565b613644906140f9565b6001600160801b039150600201541690565b50505050505f90565b805f52600960205260405f2060ff600182015460a01c165f1461368f575050600490565b805460f81c6136e4575460a01c64ffffffffff1642106136df576136b2816135f8565b905f5260096020526001600160801b0380600260405f200154169116105f146136da57600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f20541615158061381b575b80613803575b6137ec578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f20541692836137b7575b1692836137a1575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f206001815401905561375a565b6137d6835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613752565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613715565b50858116151561370f565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361385857565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805115612c195760200190565b8051821015612c195760209160051b010190565b906138c56001600160801b03604084015116602061010085015101519061438a565b6001600160801b0381511660e084015164ffffffffff60c0860151168215613f84578015613f5a5781518015613f30577f00000000000000000000000000000000000000000000000000000000000000008111613eff575064ffffffffff604061392e84613882565b51015116811015613ea857505f905f905f81515f905b808210613e17575050505064ffffffffff421664ffffffffff8216811015613dd75750506001600160801b0316808203613da057505060075492835f52600960205260405f20916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613add8951995f198b019061388f565b51015160c81b169560f01b1691161717171784555f5b818110613cd2575050600185016007556001600160a01b0360208301511680156106cf57613b29866001600160a01b03926136eb565b16613ca257613b546001600160a01b036060840151166001600160801b03835116903090339061445c565b6001600160801b0360208201511680613c72575b507f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd644360206001600160a01b03845116926001600160a01b038286015116946001600160a01b0360608201511696613c67613c4860808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a613bf18c612816565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061276d565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b613c9c906001600160a01b036060850151166001600160a01b03610100860151511690339061445c565b5f613b68565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b865f52600a60205260405f2090613ced8160e087015161388f565b51825468010000000000000000811015610fed5760018101808555811015612c19576001935f5260205f2001906001600160801b03815116908254917fffffff00000000000000000000000000000000000000000000000000000000007cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff00000000000000000000000000000000602086015160801b1694015160c01b169316171717905501613af3565b60449250604051917fd90b7e3900000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b9193509193613e3b906001600160801b03613e32858861388f565b515116906140de565b9364ffffffffff806040613e4f868561388f565b51015116941680851115613e6b57506001849301909291613944565b8385606492604051927f9588ac09000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff6040613eb984613882565b5101516040517ff539a17c00000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f4757689b0000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f3952c64e000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f20541691823314928315613ff0575b508215613fde57505090565b909150613feb33926128b5565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f613fd2565b805f52600960205261402a600260405f2001612c80565b815f52600960205260405f2060ff600182015460a01c165f1461405a57506001600160801b039150602001511690565b5460f81c61406c5750613644906135f8565b61364491506001600160801b0360408183511692015116906128d7565b3d156140b3573d9061409a82612885565b916140a86040519384612863565b82523d5f602084013e565b606090565b613644906140c581614013565b905f526009602052600260405f20015460801c906128d7565b9190916001600160801b038080941691160191821161163157565b61412b64ffffffffff825f526009602052808060405f2054818160a01c1693849160c81c160316918142160316614527565b90805f52600a60205260405f2090815415612c195767ffffffffffffffff915f5261418460205f2054825f52600960205261417f6001600160801b039586600260405f2001541695869360801c1690614611565b61467e565b918213614199575061419590614763565b1690565b9150505f526009602052600260405f20015460801c90565b64ffffffffff80421691805f526009602052604092835f20938051916141d683612846565b85549361012061425c60026001600160a01b03998a8916885260208801988a8160a01c168a528a8160c81c16888a015260ff8160f01c16151560608a015260f81c1515608089015260ff60019b600183015490811660a08b0152818160a01c16151560c08b0152818160a81c16151560e08b015260b01c16151561010089015201612c80565b94019384525f52600a602052614273825f20612cb4565b905f95808461428185613882565b510151169782825f9a5b16106143545750916142fd61417f9261430295946001600160801b039a81808d6142b5848961388f565b5151169b8c9967ffffffffffffffff60206142d0878c61388f565b510151169883826142e1888461388f565b51015116958061433a57505050511680925b0316920316614527565b614611565b91821361431a57506143148391614763565b16011690565b83929391506020905101511680918316115f14614335575090565b905090565b6143499293505f19019061388f565b5101511680926142f3565b8098976001600160801b03908161436b8b8861388f565b5151160116970197828280876143818d8961388f565b5101511661428b565b91909160405161439981612816565b5f81525f6020820152926001600160801b039182811691821561443e5767016345785d8a000080821161440757506143d2849184615317565b16602086019281845211156143f357826143ee925116906128d7565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050905060405161445081612816565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117610fed576144cb9260405261479e565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526144cb91614522606483612863565b61479e565b600160ff1b808214908115614607575b506145dd575f8112156145d45761455c815f035b5f8412156145cd57835f0390614832565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614596575f19911813156145915790565b5f0390565b60449250604051917fd49c26b300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390614832565b61455c8161454b565b60046040517f9fe2b450000000000000000000000000000000000000000000000000000000008152fd5b905082145f614537565b8061462b575061462757670de0b6b3a764000090565b5f90565b90670de0b6b3a7640000808314614678575080614650575050670de0b6b3a764000090565b670de0b6b3a764000081146146745761466f9061417f61364493614928565b614a65565b5090565b91505090565b600160ff1b808214908115614759575b5061472f575f811215614726576146b3815f035b5f84121561471f57835f0390615317565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116146e8575f19911813156145915790565b60449250604051917f120b5b4300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b8390615317565b6146b3816146a2565b60046040517fa6070c25000000000000000000000000000000000000000000000000000000008152fd5b905082145f61468e565b5f811261476d5790565b602490604051907f2463f3d50000000000000000000000000000000000000000000000000000000082526004820152fd5b5f806001600160a01b036147c793169360208151910182865af16147c0614089565b90836153c5565b805190811515918261480e575b50506147dd5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261029a576020015180159081150361029a575f806147d4565b670de0b6b3a7640000915f1983830992808302928380861095039480860395146148ec57828510156148b0579082910960018219018216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156148fa570490565b634e487b7160e01b5f52601260045260245ffd5b80156148fa576ec097ce7bc90715b34b9f10000000000590565b805f821315614a3457670de0b6b3a764000091828112614a1257506001915b8082056001600160801b03811160071b90811c9067ffffffffffffffff821160061b91821c63ffffffff811160051b90811c61ffff811160041b90811c60ff811160031b90811c91600f831160021b92831c93600196600160038711811b96871c1196171717171717179180830293831d92818414614a0757506706f05b59d3b20000925b5f84136149db57505050500290565b808291020592671bc16d674ec800008412156149fa575b821d926149cc565b8093940193821d926149f2565b925093925050020290565b5f1992915080156148fa576ec097ce7bc90715b34b9f10000000000590614947565b602482604051907f059b101b0000000000000000000000000000000000000000000000000000000082526004820152fd5b5f811215614a925768033dd1780914b971141981126136df57614a89905f03614a65565b6136449061490e565b680a688906bd8affffff81136152e657670de0b6b3a764000080604092831b05907780000000000000000000000000000000000000000000000067ff0000000000000083166151c9575b66ff00000000000083166150c1575b65ff00000000008316614fc1575b64ff000000008316614ec9575b63ff0000008316614dd9575b62ff00008316614cf1575b61ff008316614c11575b60ff8316614b3a575b02911c60bf031c90565b60808316614bff575b838316614bed575b60208316614bdb575b60108316614bc9575b60088316614bb7575b60048316614ba5575b60028316614b93575b6001831615614b30576801000000000000000102831c614b30565b6801000000000000000102831c614b78565b6801000000000000000302831c614b6f565b6801000000000000000602831c614b66565b6801000000000000000b02831c614b5d565b6801000000000000001602831c614b54565b6801000000000000002c02831c614b4b565b6801000000000000005902831c614b43565b6180008316614cdf575b6140008316614ccd575b6120008316614cbb575b6110008316614ca9575b6108008316614c97575b6104008316614c85575b6102008316614c73575b610100831615614b2757680100000000000000b102831c614b27565b6801000000000000016302831c614c57565b680100000000000002c602831c614c4d565b6801000000000000058c02831c614c43565b68010000000000000b1702831c614c39565b6801000000000000162e02831c614c2f565b68010000000000002c5d02831c614c25565b680100000000000058b902831c614c1b565b628000008316614dc7575b624000008316614db5575b622000008316614da3575b621000008316614d91575b620800008316614d7f575b620400008316614d6d575b620200008316614d5b575b62010000831615614b1d576801000000000000b17202831c614b1d565b680100000000000162e402831c614d3e565b6801000000000002c5c802831c614d33565b68010000000000058b9102831c614d28565b680100000000000b172102831c614d1d565b68010000000000162e4302831c614d12565b680100000000002c5c8602831c614d07565b6801000000000058b90c02831c614cfc565b63800000008316614eb7575b63400000008316614ea5575b63200000008316614e93575b63100000008316614e81575b63080000008316614e6f575b63040000008316614e5d575b63020000008316614e4b575b6301000000831615614b125768010000000000b1721802831c614b12565b6801000000000162e43002831c614e2d565b68010000000002c5c86002831c614e21565b680100000000058b90c002831c614e15565b6801000000000b17217f02831c614e09565b680100000000162e42ff02831c614dfd565b6801000000002c5c85fe02831c614df1565b68010000000058b90bfc02831c614de5565b6480000000008316614faf575b6440000000008316614f9d575b6420000000008316614f8b575b6410000000008316614f79575b6408000000008316614f67575b6404000000008316614f55575b6402000000008316614f43575b640100000000831615614b0657680100000000b17217f802831c614b06565b68010000000162e42ff102831c614f24565b680100000002c5c85fe302831c614f17565b6801000000058b90bfce02831c614f0a565b68010000000b17217fbb02831c614efd565b6801000000162e42fff002831c614ef0565b68010000002c5c8601cc02831c614ee3565b680100000058b90c0b4902831c614ed6565b6580000000000083166150af575b65400000000000831661509d575b65200000000000831661508b575b651000000000008316615079575b650800000000008316615067575b650400000000008316615055575b650200000000008316615043575b65010000000000831615614af9576801000000b17218355102831c614af9565b680100000162e430e5a202831c615023565b6801000002c5c863b73f02831c615015565b68010000058b90cf1e6e02831c615007565b680100000b1721bcfc9a02831c614ff9565b68010000162e43f4f83102831c614feb565b680100002c5c89d5ec6d02831c614fdd565b6801000058b91b5bc9ae02831c614fcf565b668000000000000083166151b7575b664000000000000083166151a5575b66200000000000008316615193575b66100000000000008316615181575b6608000000000000831661516f575b6604000000000000831661515d575b6602000000000000831661514b575b6601000000000000831615614aeb5768010000b17255775c0402831c614aeb565b6801000162e525ee054702831c61512a565b68010002c5cc37da949202831c61511b565b680100058ba01fb9f96d02831c61510c565b6801000b175effdc76ba02831c6150fd565b680100162f3904051fa102831c6150ee565b6801002c605e2e8cec5002831c6150df565b68010058c86da1c09ea202831c6150d0565b67800000000000000083166152c7575b67400000000000000083166152b5575b67200000000000000083166152a3575b6710000000000000008316615291575b670800000000000000831661527f575b670400000000000000831661526d575b670200000000000000831661525b575b670100000000000000831615614adc57680100b1afa5abcbed6102831c614adc565b68010163da9fb33356d802831c615239565b680102c9a3e778060ee702831c615229565b6801059b0d31585743ae02831c615219565b68010b5586cf9890f62a02831c615209565b6801172b83c7d517adce02831c6151f9565b6801306fe0a31b7152df02831c6151e9565b5077b504f333f9de6484800000000000000000000000000000006151d9565b602490604051907f0360d0280000000000000000000000000000000000000000000000000000000082526004820152fd5b9091905f19838209838202918280831092039180830392146153b457670de0b6b3a7640000908183101561537d57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061540457508051156153da57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061544f575b615415575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561540d56fea164736f6c6343000817000a"; + hex"60c0604052346103e4576158d66060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260016007556154c8908161040e8239608051816137b2015260a051818181610bdd015261387c0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461274857508063027b67441461272657806306fdde0314612632578063081812fc14612614578063095ea7b31461250f5780631400ecec1461245e5780631c1cdd4c146123d55780631e99d569146123b857806323b872dd1461239f57806331df3d481461228c57806340e58ee514611f65578063425d30dd14611f1357806342842e0e14611ee957806342966c6814611d0c5780634426757014611ce55780634857501f14611c5b5780634869e12d14611c1f5780634cc55e1114611b2657806354c022921461187057806357404b12146117d85780636352211e146117a85780636d0cee75146117a857806370a082311461173d57806375829def146116cb5780637cad6cd1146115bf5780637de6b1db146113bf5780638659c27014611021578063894e9a0d14610cec5780638f69b99314610c515780639067b67714610c005780639188ec8414610bc557806395d89b4114610ab8578063a22cb46514610a02578063a80fc071146109af578063ad35efd41461093c578063b2564569146108ea578063b637b8651461088e578063b88d4fde14610800578063b8a3be66146107cb578063b971302a1461077b578063bc2be1be1461072a578063c156a11d14610605578063c87b56dd146104e9578063d4dbd20b14610496578063d511609f14610449578063d975dfed146103fc578063e985e9c5146103a9578063ea5ead191461037a578063eac8f5b814610327578063f590c176146102ca578063f851a440146102a45763fdd46d601461025a575f80fd5b346102a15760603660031901126102a157610273612873565b6044356001600160801b038116810361029d5761029a916102926137a8565b600435613476565b80f35b8280fd5b80fd5b50346102a157806003193601126102a1576001600160a01b036020915416604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760016040826020946001600160a01b0394526009855220015416604051908152f35b50346102a15760403660031901126102a15761029a60043561039a612873565b6103a382614083565b91613079565b50346102a15760403660031901126102a1576001600160a01b0360406103cd61285d565b92826103d7612873565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883614083565b6001600160801b0360405191168152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081602093600293526009845220015460801c604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760036040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760203660031901126102a15760043561050781613506565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9081156105fa578291610577575b6040516020808252819061057390820185612838565b0390f35b90503d8083833e6105888183612a0a565b81019060208183031261029d5780519067ffffffffffffffff82116105f6570181601f8201121561029d578051926105bf84612a2c565b926105cd6040519485612a0a565b848452602085840101116102a15750610573926105f09160208085019101612817565b5f61055d565b8380fd5b6040513d84823e3d90fd5b50346102a15760403660031901126102a15760043590610623612873565b9161062c6137a8565b808252600960205260ff600160408420015460a81c161561071857805f5260036020526001600160a01b0360405f205416928333036107005761066e82614083565b6001600160801b0381166106ef575b506001600160a01b038116156106dc5761069f826001600160a01b039261365c565b16806106b85760248383637e27328960e01b8252600452fd5b908382036106c4578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b6106fa908584613079565b5f61067d565b63216caf0d60e01b8352600482905233602452604483fd5b6024925062b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c1615610316576040816020936001600160a01b03935260098452205416604051908152f35b50346102a15760203660031901126102a15760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346102a15760803660031901126102a15761081a61285d565b610822612873565b906064359067ffffffffffffffff82116105f657366023830112156105f6578160040135928461085185612a2c565b9361085f6040519586612a0a565b858552366024878301011161088a578561029a96602460209301838801378501015260443591612f35565b5080fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081610573936108d69352600a60205220612eae565b604051918291602083526020830190612908565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460b01c166040519015158152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610975906135c8565b60405190600581101561098a57602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760026040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760403660031901126102a157610a1c61285d565b6024359081151580920361029d576001600160a01b0316908115610a8c57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346102a157806003193601126102a1576040519080600254908160011c91600181168015610bbb575b602084108114610ba757838652908115610b805750600114610b23575b61057384610b0f81860382612a0a565b604051918291602083526020830190612838565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610b6657509091508101602001610b0f82610aff565b919260018160209254838588010152019101909291610b4d565b60ff191660208087019190915292151560051b85019092019250610b0f9150839050610aff565b602483634e487b7160e01b81526022600452fd5b92607f1692610ae2565b50346102a157806003193601126102a15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610c8a906135c8565b9060058210159081610ccb5760028314918215610cdf575b8215610cb6575b6020836040519015158152f35b909150610ccb57506004602091145f80610ca9565b80634e487b7160e01b602492526021600452fd5b5060038314915080610ca2565b50346102a15760203660031901126102a15760043590604051610180810181811067ffffffffffffffff82111761100d576060916101609160405283815283602082015283604082015283838201528360808201528360a08201528360c08201528360e08201528361010082015283610120820152610d69612e5e565b6101408201520152818152600960205260ff600160408320015460a81c161561031657815f52600960205260405f2060405190610da5826129ed565b8054916001600160a01b0383168152602081019364ffffffffff8460a01c168552604082019264ffffffffff8560c81c168452606083019360ff8660f01c1615158552608084019560f81c1515865260018201549260a08501956001600160a01b038516875260c086019060ff8660a01c1615158252610e46600260e089019660ff8960a81c161515885260ff6101008b019960b01c161515895201612e7c565b61012088019081526002610e598d6135c8565b610e628161297a565b14611005575b5197516001600160a01b0316935164ffffffffff1690511515915115159451151595511515968b5f52600360205260405f20546001600160a01b03169b8452600a6020526040842090516001600160a01b03169a5164ffffffffff169951151593506040519a610eda6101808d612a0a565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610f2e90612eae565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057391612908565b838252610e68565b602483634e487b7160e01b81526041600452fd5b50346102a15760203660031901126102a15760043567ffffffffffffffff811161088a576110539036906004016128d7565b9061105c6137a8565b82915b80831061106a578380f35b611075838284612ded565b359261107f6137a8565b835f52600960205260ff600160405f20015460a81c16156113ac578385526009602052604085206001015460a01c60ff16156110c85760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c61139a576110fd815f5260096020526001600160a01b0360405f205416331490565b156113845761110b81613539565b90805f526009602052611123600260405f2001612e7c565b916001600160801b038351166001600160801b038216101561137157815f52600960205260ff60405f205460f01c161561135e579061117a826001600160801b036020818796818d99511603169501511690612a7e565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215611339575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506112966001600160a01b03600160405f200154169461126e8b85886144dd565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6112da575b505050505050600101919061105f565b813b1561133557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161131d575b808080806112ca565b9061132791612a0a565b835f126105f657835f611314565b8580fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556111c4565b506339c6dc7360e21b8652600452602485fd5b506322cad1af60e11b8652600452602485fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b838562b8e7e760e51b8152602491600452fd5b50346102a15760203660031901126102a157600435906113dd6137a8565b818152600960205260ff600160408320015460a81c161561031657611401826135c8565b61140a8161297a565b600481036114255750602491634a5541ef60e01b8252600452fd5b61142e8161297a565b60038103611449575060249163fe19f19f60e01b8252600452fd5b6002906114558161297a565b146115ad57611478825f5260096020526001600160a01b0360405f205416331490565b1561158e57818152600960205260ff604082205460f01c161561157c57818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a1805f5260036020526001600160a01b0360405f20541690813b61151e575050f35b813b156115785782916024839260405195869384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611565579050f35b61156e91612a0a565b805f126102a15780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b82526004526001600160a01b033316602452fd5b6024916322cad1af60e11b8252600452fd5b50346102a15760203660031901126102a1576004356001600160a01b03811680910361088a576001600160a01b0382541633810361169c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116885760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346102a15760203660031901126102a1576116e561285d565b9080546001600160a01b03811633810361169c57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346102a15760203660031901126102a1576001600160a01b0361175f61285d565b16801561177c578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346102a15760203660031901126102a15760206117c7600435613506565b6001600160a01b0360405191168152f35b50346102a15760203660031901126102a157600435906117f6612e46565b50818152600960205260ff600160408320015460a81c1615610316579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c16825191611848836129d1565b8252602082015261186e8251809264ffffffffff60208092828151168552015116910152565bf35b50346102a15760203660031901126102a1576004359067ffffffffffffffff82116102a15781360361012060031982011261088a576118ad6137a8565b60c4830135906022190181121561088a57820160048101359067ffffffffffffffff821161029d5760240190606081023603821361029d57906118f1913691612d21565b8051916118fd83612d09565b9261190b6040519485612a0a565b808452601f1961191a82612d09565b01825b818110611b0f57505064ffffffffff4216926001600160801b0361194082613802565b51511667ffffffffffffffff602061195784613802565b5101511664ffffffffff80604061196d86613802565b510151168701169060405192611982846129b5565b83526020830152604082015261199786613802565b526119a185613802565b5060015b828110611a7b575050506119bb84600401612e25565b906119c860248601612e25565b906119d560448701612e11565b6064870135916001600160a01b0383168093036102a1576020611a73611a33611a688b8b8b8b8b8b6001600160801b038c6001600160a01b03611a1a60848a01612e39565b9481611a2860a48c01612e39565b976040519d8e612984565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612dbe565b610100820152613823565b604051908152f35b806001600160801b03611a906001938561380f565b51511667ffffffffffffffff6020611aa8848761380f565b5101511664ffffffffff806040611ac25f1987018d61380f565b51015116816040611ad3878a61380f565b5101511601169060405192611ae7846129b5565b835260208301526040820152611afd828961380f565b52611b08818861380f565b50016119a5565b602090611b1a612e5e565b8282890101520161191d565b50346102a15760403660031901126102a15760043567ffffffffffffffff811161088a57611b589036906004016128d7565b9060243567ffffffffffffffff81116105f657611b799036906004016128d7565b611b816137a8565b808403611bef57845b848110611b95578580f35b80611be9611ba66001938888612ded565b35611bb2838989612ded565b35895260036020526001600160a01b0360408a205416611bdb611bd685888a612ded565b612e11565b91611be46137a8565b613476565b01611b8a565b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883613fd3565b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c16156103165780611c96836135c8565b926005841015611cd157600260209403611cb7575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80611cab565b602482634e487b7160e01b81526021600452fd5b50346102a157806003193601126102a15760206001600160a01b0360085416604051908152f35b50346102a15760203660031901126102a157600435611d296137a8565b808252600960205260ff600160408420015460a81c161561099e57808252600960205260ff600160408420015460a01c1615611ebe57611d6881613f61565b15611ea85780825260036020526001600160a01b03604083205416151580611ea1575b80611e84575b611e72577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b036040832054168015908115611e3b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611e29575080f35b637e27328960e01b8252600452602490fd5b611e5a835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f19019055611ddf565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c1615611d91565b5081611d8b565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346102a15761029a611efb3661289d565b9060405192611f0b602085612a0a565b858452612f35565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460a01c166040519015158152f35b50346121fa5760203660031901126121fa5760043590611f836137a8565b815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c165f14611fcd5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c61226857612000815f5260096020526001600160a01b0360405f205416331490565b156122495761200e81613539565b90805f526009602052612026600260405f2001612e7c565b916001600160801b038351166001600160801b038216101561223657815f52600960205260ff60405f205460f01c161561222357806001600160801b0360208161207a948188511603169501511690612a7e565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b038116919082156121fe575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061216e6001600160a01b03600160405f200154169461126e8b85886144dd565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6121a5578580f35b813b156121fa575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e7575b808080808580f35b6121f391505f90612a0a565b5f806121df565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556120c4565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa5760043567ffffffffffffffff81116121fa5761014060031982360301126121fa576122c66137a8565b604051906122d382612984565b6122df81600401612889565b82526122ed60248201612889565b60208301526122fe60448201612a48565b604083015260648101356001600160a01b03811681036121fa5760608301526123296084820161296d565b608083015261233a60a4820161296d565b60a083015261234b60c48201612cf7565b60c083015260e481013567ffffffffffffffff81116121fa57810191366023840112156121fa57611a68611a739261238f6020953690602460048201359101612d21565b60e0840152610104369101612dbe565b346121fa576123b66123b03661289d565b91612ab2565b005b346121fa575f3660031901126121fa576020600754604051908152f35b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d5761240d906135c8565b600581101561243957806020911590811561242e575b506040519015158152f35b600191501482612423565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d576020905f90805f526009835260ff60405f205460f01c16806124f3575b6124c1575b506001600160801b0360405191168152f35b6124ed9150805f52600983526124e76001600160801b03600260405f2001541691613539565b90612a7e565b826124af565b50805f526009835260ff600160405f20015460a01c16156124aa565b346121fa5760403660031901126121fa5761252861285d565b60243561253481613506565b33151580612601575b806125ce575b6125a25781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612543565b50336001600160a01b038216141561253d565b346121fa5760203660031901126121fa5760206117c7600435612a5c565b346121fa575f3660031901126121fa576040515f6001548060011c9060018116801561271c575b602083108114612708578285529081156126e45750600114612686575b61057383610b0f81850382612a0a565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106126ca57509091508101602001610b0f612676565b9192600181602092548385880101520191019092916126b2565b60ff191660208086019190915291151560051b84019091019150610b0f9050612676565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612659565b346121fa575f3660031901126121fa57602060405167016345785d8a00008152f35b346121fa5760203660031901126121fa57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036121fa57817f80ac58cd00000000000000000000000000000000000000000000000000000000602093149081156127ed575b81156127c3575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836127bc565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506127b5565b5f5b8381106128285750505f910152565b8181015183820152602001612819565b9060209161285181518092818552858086019101612817565b601f01601f1916010190565b600435906001600160a01b03821682036121fa57565b602435906001600160a01b03821682036121fa57565b35906001600160a01b03821682036121fa57565b60609060031901126121fa576004356001600160a01b03811681036121fa57906024356001600160a01b03811681036121fa579060443590565b9181601f840112156121fa5782359167ffffffffffffffff83116121fa576020808501948460051b0101116121fa57565b90602080835192838152019201905f5b8181106129255750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612918565b359081151582036121fa57565b6005111561243957565b610120810190811067ffffffffffffffff8211176129a157604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176129a157604052565b6040810190811067ffffffffffffffff8211176129a157604052565b610140810190811067ffffffffffffffff8211176129a157604052565b90601f8019910116810190811067ffffffffffffffff8211176129a157604052565b67ffffffffffffffff81116129a157601f01601f191660200190565b35906001600160801b03821682036121fa57565b612a6581613506565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b038211612a9e57565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b03168015612ce457815f5260036020526001600160a01b0360405f205416151580612cdc575b80612cbf575b612cac577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612bf7575b6001600160a01b03935085612bc0575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612ba857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612bdf825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b47565b9192905080612c55575b15612c0e57828291612b37565b8284612c2657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612c83575b80612c015750825f526005602052336001600160a01b0360405f20541614612c01565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c60565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615612ae7565b506001612ae1565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff821682036121fa57565b67ffffffffffffffff81116129a15760051b60200190565b929192612d2d82612d09565b93612d3b6040519586612a0a565b60606020868581520193028201918183116121fa57925b828410612d5f5750505050565b6060848303126121fa5760405190612d76826129b5565b612d7f85612a48565b825260208501359067ffffffffffffffff821682036121fa5782602092836060950152612dae60408801612cf7565b6040820152815201930192612d52565b91908260409103126121fa57604051612dd6816129d1565b6020808294612de481612889565b84520135910152565b9190811015612dfd5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036121fa5790565b356001600160a01b03811681036121fa5790565b3580151581036121fa5790565b60405190612e53826129d1565b5f6020838281520152565b60405190612e6b826129b5565b5f6040838281528260208201520152565b90604051612e89816129b5565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612eba81612d09565b92612ec86040519485612a0a565b81845260208401905f5260205f205f915b838310612ee65750505050565b600160208192604051612ef8816129b5565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612ed9565b90612f41838284612ab2565b803b612f4e575b50505050565b602091612f946001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190612838565b03815f865af15f918161301c575b50612fd05750612fb0614054565b80519081612fcb5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361300a57505f808080612f48565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613071575b8161303860209383612a0a565b810103126121fa57517fffffffff00000000000000000000000000000000000000000000000000000000811681036121fa57905f612fa2565b3d915061302b565b9190916130846137a8565b805f52600960205260ff600160405f20015460a81c161561244d575f92815f52600960205260ff600160405f20015460a01c16613463576001600160a01b038116918215613438576001600160801b038416801561340c57815f5260036020526001600160a01b0360405f2054169081851415806133fc575b6133c8576001600160801b0361311284614083565b168082116133955750825f5260096020526001600160a01b0360405f20541694835f52600960205261314e87600260405f20015460801c6140a9565b5f85815260096020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561319190612e7c565b6001600160801b036131b58160208401511692826040818351169201511690612a7e565b161115613363575b835f526009602052837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160405f2001541694613206818a886144dd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a18033141580613359575b6132f1575b8333141590816132e6575b816132db575b50613264575b5050505050565b823b156132d757604051636fd110e960e01b815260048101919091523360248201526001600160a01b0390911660448201526001600160801b039092166064830152829082908183816084810103925af16132c2575b80808061325d565b6132cd828092612a0a565b6102a157806132ba565b8480fd5b90508314155f613257565b843b15159150613251565b803b156121fa57604051636fd110e960e01b8152600481018390523360248201526001600160a01b03841660448201526001600160801b03861660648201525f8160848183865af1613344575b50613246565b6133519196505f90612a0a565b5f945f61333e565b50803b1515613241565b5f84815260096020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131bd565b90837fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b84837fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061340683613f61565b156130fd565b507fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b9190915f92815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c16613463576001600160a01b038116918215613438576001600160801b038416801561340c57815f5260036020526001600160a01b0360405f2054169081851415806133fc576133c8576001600160801b0361311284614083565b805f5260036020526001600160a01b0360405f205416908115613527575090565b637e27328960e01b5f5260045260245ffd5b64ffffffffff4216815f5260096020528064ffffffffff60405f205460a01c1610156135c257815f52600960205264ffffffffff60405f205460c81c1611156135a757805f52600a602052600160405f2054115f1461359e5761359b90614189565b90565b61359b906140c9565b5f5260096020526001600160801b03600260405f2001541690565b50505f90565b805f52600960205260ff600160405f20015460a01c165f146135ea5750600490565b805f52600960205260405f205460f81c61365657805f52600960205264ffffffffff60405f205460a01c1642106136515761362481613539565b905f5260096020526001600160801b0380600260405f200154169116105f1461364c57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613796575b80613779575b613767577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613730575b1680613718575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556136d4565b61374f835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556136cd565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613681565b506001600160a01b038216151561367b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036137da57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612dfd5760200190565b8051821015612dfd5760209160051b010190565b906138456001600160801b03604084015116602061010085015101519061439f565b916001600160801b038351169060e08101519160c082019264ffffffffff8451168215613f39578015613f115781518015613ee9577f00000000000000000000000000000000000000000000000000000000000000008111613ebe575064ffffffffff60406138b384613802565b51015116811015613e7a57505f905f905f81515f905b808210613df2575050505064ffffffffff80421691169081811015613dc45750506001600160801b031690818103613d9657505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613a9e8751975f1989019061380f565b51015160c81b169360a01b169116171785555f5b818110613c88575050600187016007556001600160a01b036020830151168015612ce457613ae8886001600160a01b039261365c565b16613c5c578682613b366001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b03855116903090339061447c565b6001600160801b0360208401511680613c2c575b506001600160a01b0381511694613c21613c036001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613ba88b6129d1565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612908565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613c56906001600160a01b036060840151166001600160a01b03610100850151511690339061447c565b5f613b4a565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f2090613ca38160e087015161380f565b518254680100000000000000008110156129a15760018101808555811015612dfd576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613ab2565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613e16906001600160801b03613e0d858861380f565b515116906140a9565b9364ffffffffff806040613e2a868561380f565b51015116941680851115613e46575060018493019092916138c9565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613e8b84613802565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613fa7575b508115613f8e575090565b90506001600160a01b03613fa23392612a5c565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613f83565b805f526009602052613fea600260405f2001612e7c565b90805f52600960205260ff600160405f20015460a01c165f146140185750602001516001600160801b031690565b90815f52600960205260405f205460f81c614037575061359b90613539565b61359b91506001600160801b036040818351169201511690612a7e565b3d1561407e573d9061406582612a2c565b916140736040519384612a0a565b82523d5f602084013e565b606090565b61359b9061409081613fd3565b905f526009602052600260405f20015460801c90612a7e565b906001600160801b03809116911601906001600160801b038211612a9e57565b5f818152600960205260409020546141009064ffffffffff60a082901c811660c89290921c8116829003811691428216031661452d565b90805f52600a60205260405f20805415612dfd575f5261415567ffffffffffffffff60205f205460801c1692825f5260096020526141506001600160801b03600260405f2001541694859261460d565b614680565b918213614172575061416e6001600160801b039161475b565b1690565b90505f526009602052600260405f20015460801c90565b9064ffffffffff421691805f52600960205260405f2090604051906141ad826129ed565b61012061424060028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612e7c565b92019182525f52600a60205261425860405f20612eae565b915f9264ffffffffff604061426c83613802565b510151168664ffffffffff5f925b161061436057816142f164ffffffffff9697988784816001600160801b036142a9614150986142f69b9a61380f565b5151169a8b9867ffffffffffffffff60206142c4868b61380f565b51015116978260406142d6878461380f565b510151169480614343575050511680925b031692031661452d565b61460d565b9182136143175750906001600160801b03614311819361475b565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f1461433e575090565b905090565b6040925090614355915f19019061380f565b5101511680926142e7565b936001600160801b0360019181614377888661380f565b51511601169401958064ffffffffff8060406143938b8761380f565b5101511698929861427a565b9190916040516143ae816129d1565b5f81525f6020820152926001600160801b03821690811561445f5767016345785d8a00008111614428576143ea6001600160801b039183615381565b1660208501918183521115614414576001600160801b03918261440f92511690612a7e565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614470816129d1565b5f81525f602082015290565b9091926001600160a01b036144db9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526144d6608483612a0a565b614790565b565b6144db926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526144d6606483612a0a565b600160ff1b81148015614600575b6145d8575f8112156145cf5761455f815f035b5f8412156145c857835f039061481e565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614599575f19911813156145945790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061481e565b61455f8161454e565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461453b565b80614627575061462357670de0b6b3a764000090565b5f90565b90670de0b6b3a76400008214614672578061464a575050670de0b6b3a764000090565b670de0b6b3a7640000811461466e576146699061415061359b93614924565b614a7b565b5090565b5050670de0b6b3a764000090565b600160ff1b8114801561474e575b614726575f81121561471d576146b2815f035b5f84121561471657835f0390615381565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116146e7575f19911813156145945790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390615381565b6146b2816146a1565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461468e565b5f81126147655790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b036147b993169360208151910182865af16147b2614054565b908361542f565b80519081151591826147fa575b50506147cf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126121fa57602001518015908115036121fa575f806147c6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146148e957818410156148af57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156148f6570490565b634e487b7160e01b5f52601260045260245ffd5b80156148f6576ec097ce7bc90715b34b9f10000000000590565b805f811315614a5057670de0b6b3a76400008112614a3057506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614a1d57506706f05b59d3b20000905b5f82136149e75750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614a0f575b60011d906149da565b809192019160011d90614a06565b9050670de0b6b3a7640000929150020290565b5f19915080156148f6576ec097ce7bc90715b34b9f100000000005614941565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614aa85768033dd1780914b9711419811261365157614a9f905f03614a7b565b61359b9061490a565b680a688906bd8affffff811361535657670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff000000000000008216615221575b670de0b6b3a76400009066ff0000000000008316615111575b65ff00000000008316615009575b64ff000000008316614f09575b63ff0000008316614e11575b62ff00008316614d21575b61ff008316614c39575b60ff8316614b59575b029060401c60bf031c90565b60808316614c26575b60408316614c13575b60208316614c00575b60108316614bed575b60088316614bda575b60048316614bc7575b60028316614bb4575b6001831615614b4d57680100000000000000010260401c614b4d565b680100000000000000010260401c614b98565b680100000000000000030260401c614b8f565b680100000000000000060260401c614b86565b6801000000000000000b0260401c614b7d565b680100000000000000160260401c614b74565b6801000000000000002c0260401c614b6b565b680100000000000000590260401c614b62565b6180008316614d0e575b6140008316614cfb575b6120008316614ce8575b6110008316614cd5575b6108008316614cc2575b6104008316614caf575b6102008316614c9c575b610100831615614b4457680100000000000000b10260401c614b44565b680100000000000001630260401c614c7f565b680100000000000002c60260401c614c75565b6801000000000000058c0260401c614c6b565b68010000000000000b170260401c614c61565b6801000000000000162e0260401c614c57565b68010000000000002c5d0260401c614c4d565b680100000000000058b90260401c614c43565b628000008316614dfe575b624000008316614deb575b622000008316614dd8575b621000008316614dc5575b620800008316614db2575b620400008316614d9f575b620200008316614d8c575b62010000831615614b3a576801000000000000b1720260401c614b3a565b680100000000000162e40260401c614d6e565b6801000000000002c5c80260401c614d63565b68010000000000058b910260401c614d58565b680100000000000b17210260401c614d4d565b68010000000000162e430260401c614d42565b680100000000002c5c860260401c614d37565b6801000000000058b90c0260401c614d2c565b63800000008316614ef6575b63400000008316614ee3575b63200000008316614ed0575b63100000008316614ebd575b63080000008316614eaa575b63040000008316614e97575b63020000008316614e84575b6301000000831615614b2f5768010000000000b172180260401c614b2f565b6801000000000162e4300260401c614e65565b68010000000002c5c8600260401c614e59565b680100000000058b90c00260401c614e4d565b6801000000000b17217f0260401c614e41565b680100000000162e42ff0260401c614e35565b6801000000002c5c85fe0260401c614e29565b68010000000058b90bfc0260401c614e1d565b6480000000008316614ff6575b6440000000008316614fe3575b6420000000008316614fd0575b6410000000008316614fbd575b6408000000008316614faa575b6404000000008316614f97575b6402000000008316614f84575b640100000000831615614b2357680100000000b17217f80260401c614b23565b68010000000162e42ff10260401c614f64565b680100000002c5c85fe30260401c614f57565b6801000000058b90bfce0260401c614f4a565b68010000000b17217fbb0260401c614f3d565b6801000000162e42fff00260401c614f30565b68010000002c5c8601cc0260401c614f23565b680100000058b90c0b490260401c614f16565b6580000000000083166150fe575b6540000000000083166150eb575b6520000000000083166150d8575b6510000000000083166150c5575b6508000000000083166150b2575b65040000000000831661509f575b65020000000000831661508c575b65010000000000831615614b16576801000000b1721835510260401c614b16565b680100000162e430e5a20260401c61506b565b6801000002c5c863b73f0260401c61505d565b68010000058b90cf1e6e0260401c61504f565b680100000b1721bcfc9a0260401c615041565b68010000162e43f4f8310260401c615033565b680100002c5c89d5ec6d0260401c615025565b6801000058b91b5bc9ae0260401c615017565b6680000000000000831661520e575b664000000000000083166151fb575b662000000000000083166151e8575b661000000000000083166151d5575b660800000000000083166151c2575b660400000000000083166151af575b6602000000000000831661519c575b6601000000000000831615614b085768010000b17255775c040260401c614b08565b6801000162e525ee05470260401c61517a565b68010002c5cc37da94920260401c61516b565b680100058ba01fb9f96d0260401c61515c565b6801000b175effdc76ba0260401c61514d565b680100162f3904051fa10260401c61513e565b6801002c605e2e8cec500260401c61512f565b68010058c86da1c09ea20260401c615120565b6780000000000000008216615337575b670de0b6b3a7640000906740000000000000008316615324575b6720000000000000008316615311575b67100000000000000083166152fe575b67080000000000000083166152eb575b67040000000000000083166152d8575b67020000000000000083166152c5575b67010000000000000083166152b2575b9050614aef565b680100b1afa5abcbed610260401c6152ab565b68010163da9fb33356d80260401c61529b565b680102c9a3e778060ee70260401c61528b565b6801059b0d31585743ae0260401c61527b565b68010b5586cf9890f62a0260401c61526b565b6801172b83c7d517adce0260401c61525b565b6801306fe0a31b7152df0260401c61524b565b5077b504f333f9de648480000000000000000000000000000000615231565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461541e57670de0b6b3a76400008210156153ee577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061546c575080511561544457805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806154b2575b61547d575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561547556fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0346200039e57601f19906001600160401b0390601f620049713881900382810186168401919085831185841017620002c05780859260409485528339810103126200039e5781516001600160a01b0380821694909290918590036200039e576020809401519283168093036200039e576200007b620003a2565b93601c85527f5361626c696572205632204c6f636b7570204c696e656172204e46540000000081860152620000af620003a2565b96601188527029a0a116ab1916a627a1a5aaa816a624a760791b82890152306080528551848111620002c0576001968754908882811c9216801562000393575b85831014620002a157818684931162000340575b508490868311600114620002e0575f92620002d4575b50505f19600383901b1c191690871b1786555b8751938411620002c0576002548681811c91168015620002b5575b83821014620002a15783811162000258575b5081928411600114620001ef57505081929394955f92620001e3575b50505f19600383901b1c191690831b176002555b60018060a01b031983815f5416175f556008541617600855604051915f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36007556145ae9081620003c38239608051816139620152f35b015190505f8062000175565b83929192169660025f52825f20925f905b89821062000240575050838697989695961062000227575b505050811b0160025562000189565b01515f1960f88460031b161c191690555f808062000218565b80888596829496860151815501950193019062000200565b60025f52825f208480870160051c82019285881062000297575b0160051c019087905b8281106200028b57505062000159565b5f81550187906200027b565b9250819262000272565b634e487b7160e01b5f52602260045260245ffd5b90607f169062000147565b634e487b7160e01b5f52604160045260245ffd5b015190505f8062000119565b90848a941691845f52865f20925f5b8882821062000329575050841162000310575b505050811b0186556200012c565b01515f1960f88460031b161c191690555f808062000302565b8385015186558d97909501949384019301620002ef565b909150885f52845f208680850160051c82019287861062000389575b918b91869594930160051c01915b8281106200037a57505062000103565b5f81558594508b91016200036a565b925081926200035c565b91607f1691620000ef565b5f80fd5b60408051919082016001600160401b03811183821017620002c05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a714612fb757508063027b674414612f9557806306fdde0314612e9f578063081812fc14612e81578063095ea7b314612d885780631400ecec14612ce85780631c1cdd4c14612c705780631e99d56914612c5357806323b872dd14612c3a57806340e58ee51461299e578063425d30dd1461294d57806342842e0e146128ff57806342966c6814612736578063442675701461270f5780634857501f146126995780634869e12d1461265e5780634cc55e11146121b657806353b157271461209757806357404b1214611fcc5780636352211e14611f9c5780636d0cee7514611f9c57806370a0823114611f2c57806375829def14611e99578063780a82c814611e4c5780637cad6cd114611d535780637de6b1db14611b2e5780638659c270146117de578063894e9a0d146114be5780638f69b993146114235780639067b677146113d357806395d89b41146112c4578063a22cb46514611209578063a80fc071146111b7578063ab167ccc1461106e578063ad35efd41461100c578063b256456914610fbb578063b88d4fde14610f2e578063b8a3be6614610ef9578063b971302a14610eaa578063bc2be1be14610e5a578063c156a11d14610995578063c87b56dd14610879578063d4dbd20b14610827578063d511609f146107db578063d975dfed1461078f578063e985e9c51461073c578063ea5ead1914610714578063eac8f5b8146106c2578063f590c17614610660578063f851a4401461063a5763fdd46d601461024f575f80fd5b34610637576060366003190112610637576004359061026c6130e2565b9161027561323f565b9261027e613958565b818352600960209181835260ff600160408720015460a81c16156106205783855281835260ff600160408720015460a01c16610608576001600160a01b03958682169283156105f0576001600160801b03938483169081156105d857878952600387528960408a2054169283821415806105c8575b6105a4576103008961412d565b87811684116105725750888a5280885260408a20968360028d8a541699015460801c0181811161055e57988b9c8b9c9a937f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d936103928e96859f8f60408161038d9360029352878a5220019182906001600160801b036001600160801b031983549260801b169116179055565b61351d565b906103ae81868401511692826040818351169201511690613277565b16111561052f575b848c528252600160408c20015416946103d0818a88614153565b604051908152a48033141580610525575b6104b7575b8333141590816104ac575b816104a1575b5061042b575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b1561049d57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af1610485575b80806103fd565b61048e9061315e565b61049957825f61047e565b8280fd5b8380fd5b90508314155f6103f7565b843b151591506103f1565b803b1561052157604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161050d575b50506103e6565b6105169061315e565b61052157845f610506565b8480fd5b50803b15156103e1565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103b6565b60248c634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105d2896139b4565b156102f3565b6024886040519063d2aabcd960e01b82526004820152fd5b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b80fd5b50346106375780600319360112610637576001600160a01b036020915416604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760016040836001600160a01b0393602095526009855220015416604051908152f35b503461063757604036600319011261063757600435906107326130e2565b916102758161412d565b5034610637576040366003190112610637576107566130cc565b60406107606130e2565b926001600160a01b03809316815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346106375760203660031901126106375760ff6001604060043593848152600960205220015460a81c16156106ab576107ca60209161412d565b6001600160801b0360405191168152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57604082600292602094526009845220015460801c604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760036040836001600160801b0393602095526009855220015416604051908152f35b50346106375760208060031936011261098557600435610898816136cc565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610989578093610908575b50506109046040519282849384528301906130a7565b0390f35b909192503d8082843e61091b8184613201565b82019183818403126109855780519067ffffffffffffffff8211610499570182601f820112156109855780519161095183613223565b9361095f6040519586613201565b83855285848401011161063757509061097d91848085019101613086565b905f806108ee565b5080fd5b604051903d90823e3d90fd5b5034610637576040366003190112610637576004356109b26130e2565b6109ba613958565b81835260099060209082825260ff600160408720015460a81c161561062057838552600382526001600160a01b03918260408720541693843303610e3b57610a018661412d565b906001600160801b039081831680158015610aa1575b50505050505081811615610a895783610a2f9161381d565b90811680610a4f5760248460405190637e27328960e01b82526004820152fd5b8203610a59578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610aa9613958565b898b5282865260ff600160408d20015460a81c1615610e2457898b5282865260ff600160408d20015460a01c16610e0c578815610df457610ddc57888a52600385528660408b205416918289141580610dcc575b610da857610b0a8a61412d565b8481168311610d765750898b5280865260408b20938260028a87541696015460801c01818111610d625790610b718d9796959493928d8952838a5261038d600260408b20019182906001600160801b036001600160801b031983549260801b169116179055565b90610b8d818a8401511692826040818351169201511690613277565b161115610d33575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610bd4818688614153565b604051908152a48033141580610d29575b610cbf575b813314159081610cb4575b81610ca9575b50610c38575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a15f8080808080610a17565b803b1561049957604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610c91575b80610c01565b610c9a9061315e565b610ca557855f610c8b565b8580fd5b90508114155f610bfb565b823b15159150610bf5565b803b1561049d57604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610d15575b5050610bea565b610d1e9061315e565b61049d57835f610d0e565b50803b1515610be5565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610b95565b60248d634e487b7160e01b81526011600452fd5b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610dd68a6139b4565b15610afd565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab576040826001600160a01b03926020945260098452205416604051908152f35b50346106375760203660031901126106375760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461063757608036600319011261063757610f486130cc565b610f506130e2565b906064359067ffffffffffffffff821161049d573660238301121561049d5781600401359284610f7f85613223565b93610f8d6040519586613201565b85855236602487830101116109855785610fb896602460209301838801378501015260443591613565565b80f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57600160408360ff93602095526009855220015460b01c166040519015158152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab576110459061379d565b60405190600581101561105a57602092508152f35b602483634e487b7160e01b81526021600452fd5b50346106375761014036600319011261063757611089613958565b6110916134ff565b9064ffffffffff804216808452816110a7613551565b166111a1575b60e43590828216820361119d5701166040830152600435916001600160a01b039182841680940361119d576024359083821680920361119d57604435906001600160801b03821680920361119d576064359085821680920361063757506084359182151580930361119d5760a4359384151580950361119d576040519761113389613172565b8852602088015260408701526060860152608085015260a084015260c083015260406101031936011261119d576040519161116d836131e5565b61010435918216820361119d57826111959260209452610124358482015260e0820152613a92565b604051908152f35b5f80fd5b816111aa613551565b82011660208501526110ad565b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760026040836001600160801b0393602095526009855220015416604051908152f35b5034610637576040366003190112610637576112236130cc565b6024359081151580920361119d576001600160a01b031690811561129357338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461063757806003193601126106375760405190806002549160018360011c92600185169485156113c9575b60209586861081146113b557858852879493929187908215611393575050600114611339575b505061132592500383613201565b6109046040519282849384528301906130a7565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b85831061137b57505061132593508201015f80611317565b80548389018501528794508693909201918101611363565b925093505061132594915060ff191682840152151560051b8201015f80611317565b602483634e487b7160e01b81526022600452fd5b93607f16936112f1565b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5761145c9061379d565b906005821015908161149d57600283149182156114b1575b8215611488575b6020836040519015158152f35b90915061149d57506004602091145f8061147b565b80634e487b7160e01b602492526021600452fd5b506003831491505f611474565b503461063757602036600319011261063757806101606040516114e0816131ab565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526115236134ff565b61014082015201526004358152600960205260ff600160408320015460a81c16156117c6576004358152600960205260408120906115f1600260405193611569856131c8565b80546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c1615156101008601520161351d565b61012083015261160260043561379d565b60058110156117b2576101606101c093600264ffffffffff93146117a7575b610120810151936001600160a01b0360a083015116946004358252600a60205284604083205416918560408501511690606085015115159761010086015115159260c08701511515916001600160a01b03604060e08a015115159560036020522054166001600160a01b038951169b8960808d8f9c60200151169101511515926040519b6116ae8d6131ab565b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152828201526040519384526001600160a01b0360208201511660208501528260408201511660408501526060810151151560608501526080810151151560808501526001600160a01b0360a08201511660a08501528260c08201511660c085015260e0810151151560e08501526101008101511515610100850152610120810151151561012085015261014081015160406001600160801b03918281511661014088015282602082015116858801520151166101808501520151166101a0820152f35b836060820152611621565b602482634e487b7160e01b81526021600452fd5b602460405162b8e7e760e51b81526004356004820152fd5b5034610637576020806003193601126109855760043567ffffffffffffffff81116104995761181190369060040161312d565b919061181b613958565b83925b808410611829578480f35b6118348482846134db565b359361183e613958565b848652600980855260ff600191818360408b20015460a81c1615611b1757878952808752604089208381015460a01c83161561188c5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611aff576118bb815f5260096020526001600160a01b0360405f205416331490565b15611adf576118c9816136ed565b93818a528289526118df600260408c200161351d565b946001600160801b0394858751168683161015611ac757838c52848b5260408c205460f01c1615611aaf57918493918a61192b85878f9a99808c9986928d511603169a01511690613277565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506119fb60408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611a96575b60038096018d6001600160801b03198254161790556001600160a01b0392838092169b8c9789522054169889965260408d20015416946119d38b8588614153565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611a3f575b50505050505060010192919061181e565b813b15610ca557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611a82575b80808080611a2e565b611a8b9061315e565b61052157845f611a79565b818601600160a01b60ff60a01b19825416179055611992565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b5034610637576020806003193601126109855760043590611b4d613958565b8183526009815260ff600160408520015460a81c1615611d3c57611b708261379d565b6005811015611d285760048103611b995760248360405190634a5541ef60e01b82526004820152fd5b60038103611bb9576024836040519063fe19f19f60e01b82526004820152fd5b600214611d1057611bde825f5260096020526001600160a01b0360405f205416331490565b15611cf1578183526009815260ff604084205460f01c1615611cd957818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611c81575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b1561049957816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611cc5575b80611c52565b611cce9061315e565b61049957825f611cbf565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b5034610637576020366003190112610637576004356001600160a01b03908181168091036104995781835416338103611e23575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e0f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab5760408264ffffffffff9260209452600a8452205416604051908152f35b503461063757602036600319011261063757611eb36130cc565b9080546001600160a01b0380821693338503611f05576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b5034610637576020366003190112610637576001600160a01b03611f4e6130cc565b168015611f6b578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b5034610637576020366003190112610637576020611fbb6004356136cc565b6001600160a01b0360405191168152f35b503461063757602090816003193601126106375760043591611fec6134ff565b508282526009815260ff600160408420015460a81c16156120805760609282526009815264ffffffffff9182604082205460a01c1692600a835260408181842054169260098552205460c81c1691604051936120478561318f565b8452830152604082015261207e60405180926040908164ffffffffff91828151168552826020820151166020860152015116910152565bf35b6024836040519062b8e7e760e51b82526004820152fd5b503461063757610160366003190112610637576120b2613958565b604051906120bf82613172565b6120c76130cc565b82526120d16130e2565b60208301526120de61323f565b60408301526001600160a01b03906064358281168103610985576060840152608435801515810361119d57608084015260a435801515810361119d5760a084015260603660c319011261063757506040516121388161318f565b64ffffffffff60c435818116810361119d57825260e435818116810361119d57602083015261010435908116810361119d57604082015260c083015260406101231936011261119d576040519161218e836131e5565b61012435918216820361119d57826111959260209452610144358482015260e0820152613a92565b50346106375760403660031901126106375767ffffffffffffffff600435818111610499576121e990369060040161312d565b909160243590811161049d5761220390369060040161312d565b61220b613958565b80830361262757845b83811061221f578580f35b61222a8185876134db565b35906122378186886134db565b35875260036020526001600160a01b036040882054166122588285876134db565b35906001600160801b038216820361119d57612272613958565b838952600960205260ff600160408b20015460a81c161561062057838952600960205260ff600160408b20015460a01c1661060857801561260f576001600160801b038216156125f75783895260036020526001600160a01b0360408a2054169182821415806125e7575b6125c3576122ea8561412d565b6001600160801b0381166001600160801b038316116125935750848a52600960205260408a20926001600160a01b038454169360026001600160801b03841691015460801c016001600160801b03811161055e579061237b8c95949392888752600960205261038d600260408920019182906001600160801b036001600160801b031983549260801b169116179055565b6001600160801b0361239f8160208401511692826040818351169201511690613277565b161115612562575b86855260096020526001600160a01b036001604087200154166123d46001600160801b0384168583614153565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a48033141580612558575b6124ee575b8333141590816124e3575b816124d8575b50612466575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a101612214565b823b1561049d57604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16124c0575b808061242f565b6124c99061315e565b6124d457865f6124b9565b8680fd5b90508314155f612429565b843b15159150612423565b803b1561052157604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1612544575b5050612418565b61254d9061315e565b61052157845f61253d565b50803b1515612413565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556123a7565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b606485836040519163b34359d360e01b835260048301523360248301526044820152fd5b506125f1856139b4565b156122dd565b6024846040519063d2aabcd960e01b82526004820152fd5b60248460405190630ff7ee2d60e31b82526004820152fd5b82604491604051917faec9344000000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50346106375760203660031901126106375760ff6001604060043593848152600960205220015460a81c16156106ab576107ca602091613a19565b50346106375760203660031901126106375760043590818152600960205260ff600160408320015460a81c1615611d3c57806126d48361379d565b9260058410156117b2576002602094036126f5575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f806126e9565b503461063757806003193601126106375760206001600160a01b0360085416604051908152f35b5034610637576020806003193601126109855760043590612755613958565b8183526009815260ff600160408520015460a81c1615611d3c578183526009815260ff600160408520015460a01c16156128ce57612792826139b4565b15611cf157815f52600381526001600160a01b038060405f2054161515806128c7575b806128ae575b612896577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f205416918215928315612860575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a1612848575080f35b60249060405190637e27328960e01b82526004820152fd5b61287f855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f1981540190556127f9565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c16156127bb565b505f6127b5565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b50346106375761290e366130f8565b60405191602083019383851067ffffffffffffffff86111761293957610fb894604052858452613565565b634e487b7160e01b5f52604160045260245ffd5b503461063757602036600319011261063757600435808252600960205260ff600160408420015460a81c16156106ab57600160408360ff93602095526009855220015460a01c166040519015158152f35b503461119d5760208060031936011261119d57600435906129bd613958565b815f52600980825260ff600160405f20015460a81c161561208057825f5280825260405f2060ff600182015460a01c165f14612a0b5760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612c2257612a31835f5260096020526001600160a01b0360405f205416331490565b15612c0357612a3f836136ed565b835f52818352612a54600260405f200161351d565b936001600160801b0391828651168382161015611d1057815f5283855260ff60405f205460f01c1615611cd957612aba818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c511603169901511690613277565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88161789558216978815612be9575b01886001600160801b03198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f2001541693612b628c8487614153565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b612b96578580f35b813b1561119d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612bd8575b808080808580f35b612be2915061315e565b5f80612bd0565b60018101600160a01b60ff60a01b19825416179055612afe565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b3461119d57612c51612c4b366130f8565b916132a4565b005b3461119d575f36600319011261119d576020600754604051908152f35b3461119d57602036600319011261119d57600435805f52600960205260ff600160405f20015460a81c16156106ab57612ca89061379d565b6005811015612cd4578060209115908115612cc9575b506040519015158152f35b600191501482612cbe565b634e487b7160e01b5f52602160045260245ffd5b3461119d57602036600319011261119d57600435805f52600960205260ff600160405f20015460a81c16156106ab576020905f90805f526009835260405f2060ff815460f01c1680612d76575b612d4d575b50506001600160801b0360405191168152f35b612d6f92506001600160801b036002612d6992015416916136ed565b90613277565b8280612d3a565b5060ff600182015460a01c1615612d35565b3461119d57604036600319011261119d57612da16130cc565b602435612dad816136cc565b33151580612e6e575b80612e44575b612e145781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f20541615612dbc565b50336001600160a01b0382161415612db6565b3461119d57602036600319011261119d576020611fbb600435613255565b3461119d575f36600319011261119d576040515f600190600154918260011c9160018416918215612f8b575b6020948585108414612f775785879486865291825f14612f57575050600114612efc575b5061132592500383613201565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b858310612f3f575050611325935082010185612eef565b80548389018501528794508693909201918101612f28565b60ff19168582015261132595151560051b8501019250879150612eef9050565b634e487b7160e01b5f52602260045260245ffd5b92607f1692612ecb565b3461119d575f36600319011261119d57602060405167016345785d8a00008152f35b3461119d57602036600319011261119d57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361119d57817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561305c575b8115613032575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361302b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613024565b5f5b8381106130975750505f910152565b8181015183820152602001613088565b906020916130c081518092818552858086019101613086565b601f01601f1916010190565b600435906001600160a01b038216820361119d57565b602435906001600160a01b038216820361119d57565b606090600319011261119d576001600160a01b0390600435828116810361119d5791602435908116810361119d579060443590565b9181601f8401121561119d5782359167ffffffffffffffff831161119d576020808501948460051b01011161119d57565b67ffffffffffffffff811161293957604052565b610100810190811067ffffffffffffffff82111761293957604052565b6060810190811067ffffffffffffffff82111761293957604052565b610180810190811067ffffffffffffffff82111761293957604052565b610140810190811067ffffffffffffffff82111761293957604052565b6040810190811067ffffffffffffffff82111761293957604052565b90601f8019910116810190811067ffffffffffffffff82111761293957604052565b67ffffffffffffffff811161293957601f01601f191660200190565b604435906001600160801b038216820361119d57565b61325e816136cc565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b03918216908216039190821161329057565b634e487b7160e01b5f52601160045260245ffd5b906001600160a01b038091169081156134c457835f526020906003825260409181835f2054161515806134bc575b806134a4575b61348d57855f526003815281835f20541693331515806133e6575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856133b1575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036133835750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b6133d0885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f19815401905561331d565b8061344c575b156133f7575f6132f3565b838786613414576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b503385148015613471575b806133ec5750865f52600582523383855f205416146133ec565b50845f5260068252835f20335f52825260ff845f205416613457565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c16156132d8565b5060016132d2565b6024604051633250574960e11b81525f6004820152fd5b91908110156134eb5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061350c8261318f565b5f6040838281528260208201520152565b9060405161352a8161318f565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b60c43564ffffffffff8116810361119d5790565b919290926135748185856132a4565b833b613581575b50505050565b6020906001600160a01b03809516946135e260405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906130a7565b03815f875af15f918161366f575b5061362657826135fe6140fe565b805191908261361f5760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000160361365757505f80808061357b565b60249060405190633250574960e11b82526004820152fd5b9091506020813d6020116136c4575b8161368b60209383613201565b8101031261119d57517fffffffff000000000000000000000000000000000000000000000000000000008116810361119d57905f6135f0565b3d915061367e565b805f5260036020526001600160a01b0360405f205416908115612848575090565b805f52600a60205264ffffffffff908160405f205416421061379757600960205260405f2091825490808260c81c1691824210156137835761373a93945060a01c168091039042036142f0565b815f5260096020526001600160801b039161375f83600260405f2001541680936143cc565b91821161376b57501690565b9150505f526009602052600260405f20015460801c90565b50505050600201546001600160801b031690565b50505f90565b805f52600960205260405f2060ff600182015460a01c165f146137c1575050600490565b805460f81c613816575460a01c64ffffffffff164210613811576137e4816136ed565b905f5260096020526001600160801b0380600260405f200154169116105f1461380c57600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f20541615158061394d575b80613935575b61391e578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f20541692836138e9575b1692836138d3575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f206001815401905561388c565b613908835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613884565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613847565b508581161515613841565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361398a57565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f205416918233149283156139f6575b5082156139e457505090565b9091506139f13392613255565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f6139d8565b805f526009602052613a30600260405f200161351d565b815f52600960205260405f2060ff600182015460a01c165f14613a6057506001600160801b039150602001511690565b5460f81c613a755750613a72906136ed565b90565b613a7291506001600160801b036040818351169201511690613277565b90613ab36001600160801b03604084015116602060e08501510151906141af565b916001600160801b0383511660c082015190156140d45764ffffffffff815116156140aa576020810164ffffffffff81511680613ffa575b5050604064ffffffffff82511691019064ffffffffff8251169081811015613fba57505064ffffffffff8042169151169081811015613f7a575050600754926001600160801b0381511660405190613b428261318f565b81525f60208201525f60408201526001600160a01b036060840151169060c08401519164ffffffffff604084015116906080860151151560a087015115159264ffffffffff6001600160a01b0389511696511660405196613ba2886131c8565b87526020870152604086015260608501525f608085015260a08401525f60c0840152600160e08401526101008301526101208201908152855f52600960205260405f20916001600160a01b0381511678ffffffffff0000000000000000000000000000000000000000602083015160a01b16907dffffffffff00000000000000000000000000000000000000000000000000604084015160c81b167eff0000000000000000000000000000000000000000000000000000000000006060850151151560f01b16917fff000000000000000000000000000000000000000000000000000000000000006080860151151560f81b169317171717835560018301906001600160a01b0360a0820151169082549174ff000000000000000000000000000000000000000060c0830151151560a01b16907fffffffffffffffffff000000000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000061010075ff00000000000000000000000000000000000000000060e0870151151560a81b16950151151560b01b1694161717171790556001600160801b036040600360028501935194613d9684875116956001600160801b03199687825416178155856020890151166001600160801b036001600160801b031983549260801b169116179055565b01930151169082541617905564ffffffffff602060c084015101511680613f5d575b50600184016007556001600160a01b0360208301511680156134c457613de6856001600160a01b039261381d565b16613f2d57613e116001600160a01b036060840151166001600160801b038351169030903390614281565b6001600160801b0360208201511680613efe575b506001600160a01b038251167f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c610140866001600160a01b0360208701511694613ef56001600160a01b03606089015116976080810151151560a08201511515906001600160801b0360206001600160a01b0360e060c087015196015151169660405198895233828a01528281511660408a01520151166060870152608086015260a085015260c08401906040908164ffffffffff91828151168552826020820151166020860152015116910152565b610120820152a4565b613f27906001600160a01b036060850151166001600160a01b0360e08601515116903390614281565b5f613e25565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b600a60205260405f209064ffffffffff198254161790555f613db8565b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517f5057f08400000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b64ffffffffff8351168181101561406a57505064ffffffffff90511664ffffffffff60408301511690818110613aeb576040517f9fee269100000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b6040517fb39831ea00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b3d15614128573d9061410f82613223565b9161411d6040519384613201565b82523d5f602084013e565b606090565b613a729061413a81613a19565b905f526009602052600260405f20015460801c90613277565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526141ad916141a8606483613201565b61447a565b565b9190916040516141be816131e5565b5f81525f6020820152926001600160801b03918281169182156142635767016345785d8a000080821161422c57506141f78491846143cc565b1660208601928184521115614218578261421392511690613277565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b505050509050604051614275816131e5565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117612939576141ad9260405261447a565b670de0b6b3a7640000915f1983830992808302928380861095039480860395146143aa578285101561436e579082910960018219018216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b82606492604051927f63a05778000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b5050809250156143b8570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461446957670de0b6b3a7640000908183101561443257947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036144a393169360208151910182865af161449c6140fe565b908361450e565b80519081151591826144ea575b50506144b95750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261119d576020015180159081150361119d575f806144b0565b9061454d575080511561452357805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580614598575b61455e575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561455656fea164736f6c6343000817000a"; + hex"60a0604052346103bf57614b456040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561475c90816103e9823960805181613aa70152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461309f57508063027b67441461307d57806306fdde0314612f89578063081812fc14612f6b578063095ea7b314612e665780631400ecec14612db55780631c1cdd4c14612d2c5780631e99d56914612d0f57806323b872dd14612cf657806340e58ee5146129e1578063425d30dd1461298f57806342842e0e1461296557806342966c681461278857806344267570146127615780634857501f146126eb5780634869e12d146126af5780634cc55e11146121f657806353b15727146120c857806357404b121461200d5780636352211e14611fdd5780636d0cee7514611fdd57806370a0823114611f7257806375829def14611f00578063780a82c814611eb25780637cad6cd114611da65780637de6b1db14611bb15780638659c2701461180d578063894e9a0d1461150b5780638f69b993146114705780639067b6771461141f57806395d89b4114611312578063a22cb4651461125c578063a80fc07114611209578063ab167ccc1461108c578063ad35efd414611019578063b256456914610fc7578063b88d4fde14610f36578063b8a3be6614610f01578063b971302a14610eb1578063bc2be1be14610e60578063c156a11d146109a8578063c87b56dd14610888578063d4dbd20b14610835578063d511609f146107e8578063d975dfed1461079b578063e985e9c514610748578063ea5ead1914610721578063eac8f5b8146106ce578063f590c17614610671578063f851a4401461064b5763fdd46d601461024f575f80fd5b346104d65760603660031901126104d6576004359061026c6131ca565b61027461332c565b9261027d613a9d565b808352600960205260ff600160408520015460a81c161561063a57808352600960205260ff600160408520015460a01c16610628576001600160a01b038216938415610615576001600160801b03811680156106025782855260036020526001600160a01b0360408620541680871415806105f2575b6105d7576001600160801b03610308856142e7565b168083116105bc575083865260096020526001600160a01b0360408720541691848752600960205280600260408920015460801c01976001600160801b0389116105a8576103808899878a526009602052600260408b2001906001600160801b036001600160801b031983549260801b169116179055565b8588526009602052610397600260408a200161361f565b6001600160801b036103bb8160208401511692826040818351169201511690613364565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c8861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916132ee565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916132ee565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b602488634e487b7160e01b81526011600452fd5b86606491848763287ecaef60e21b8452600452602452604452fd5b606486888663b34359d360e01b835260045233602452604452fd5b506105fc84613af7565b156102f3565b6024858463d2aabcd960e01b8252600452fd5b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576004359061073f6131ca565b610274836142e7565b50346104d65760403660031901126104d6576001600160a01b03604061076c6131b4565b92826107766131ca565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d7836142e7565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d6576004356108a6816137a9565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa90811561099d578291610916575b604051602080825281906109129082018561318f565b0390f35b90503d8083833e61092781836132ee565b8101906020818303126109955780519067ffffffffffffffff8211610999570181601f820112156109955780519261095e84613310565b9261096c60405194856132ee565b848452602085840101116104d657506109129261098f916020808501910161316e565b5f6108fc565b8280fd5b8380fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d657600435906109c66131ca565b916109cf613a9d565b808252600960205260ff600160408420015460a81c1615610e4e5780825260036020526001600160a01b0360408320541692833303610e3757610a11826142e7565b6001600160801b0381169081158015610a99575b5050506001600160a01b03811615610a8657610a49826001600160a01b0392613951565b1680610a625760248383637e27328960e01b8252600452fd5b90838203610a6e578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610aa1613a9d565b848652600960205260ff600160408820015460a81c1615610e2557848652600960205260ff600160408820015460a01c16610e12578615610dff57610dec5783855260036020526001600160a01b036040862054168087141580610ddc575b610dc1576001600160801b03610b15866142e7565b16808411610da6575084865260096020526001600160a01b0360408720541692858752600960205280600260408920015460801c016001600160801b0381116105a857610b8b908789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b8587526009602052610ba26002604089200161361f565b6001600160801b03610bc68160208401511692826040818351169201511690613364565b161115610d6a575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610c1881868861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610d60575b610cf5575b823314159081610cea575b81610cdf575b50610c75575b80610a25565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610c6f5781610cd4916132ee565b61099557825f610c6f565b90508214155f610c69565b833b15159150610c63565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610d4b575b5050610c58565b81610d55916132ee565b61055e57855f610d44565b50803b1515610c53565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610bce565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610de685613af7565b15610b00565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610f506131b4565b610f586131ca565b906064359067ffffffffffffffff821161099957366023830112156109995781600401359284610f8785613310565b93610f9560405195866132ee565b8585523660248783010111610fc35785610fc096602460209301838801378501015260443591613665565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b57611052906138bd565b60405190600581101561106757602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d6576101403660031901126104d6576110a7613a9d565b6110af613601565b9064ffffffffff421680835264ffffffffff6110c9613651565b166111ee575b60e4359064ffffffffff82168203610995570164ffffffffff1660408301526001600160a01b03600435908116929083810361099557506024356001600160a01b0381169081810361099957506044356001600160801b038116908181036104d957506064356001600160a01b0381168091036104d95760843591821515928381036111ea575060a43593841515948581036111e65750604051976111738961324b565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126104d657604051906111ad826132d2565b61010435906001600160a01b03821682036104d65760206111de8585858152610124358482015260e0820152613bed565b604051908152f35b8780fd5b8680fd5b64ffffffffff6111fc613651565b82011660208401526110cf565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576112766131b4565b60243590811515809203610995576001600160a01b03169081156112e657338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611415575b602084108114611401578386529081156113da575060011461137d575b61091284611369818603826132ee565b60405191829160208352602083019061318f565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106113c05750909150810160200161136982611359565b9192600181602092548385880101520191019092916113a7565b60ff191660208087019190915292151560051b850190920192506113699150839050611359565b602483634e487b7160e01b81526022600452fd5b92607f169261133c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b576114a9906138bd565b90600582101590816114ea57600283149182156114fe575b82156114d5575b6020836040519015158152f35b9091506114ea57506004602091145f806114c8565b80634e487b7160e01b602492526021600452fd5b50600383149150806114c1565b50346104d65760203660031901126104d657600435908061016060405161153181613298565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611574613601565b6101408201520152818152600960205260ff600160408320015460a81c16156106bd5781815260096020526040812091604051906115b1826132b5565b8354906001600160a01b0382168352602083019464ffffffffff8360a01c168652604084019464ffffffffff8460c81c168652606085019060ff8560f01c1615158252608086019460f81c1515855260018301549560a08101966001600160a01b038116885260c082019660ff8260a01c1615158852611652600260e085019760ff8560a81c161515895260ff61010087019560b01c16151585520161361f565b6101208401908152611663886138bd565b60058110156117f9576002146117f1575b5198516001600160a01b031693878152600a602052604081205464ffffffffff169a5164ffffffffff1695511515925115159851151596511515978152600360205260409020546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516116e981613298565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b848652611674565b602486634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff8111610fc35761183f90369060040161321a565b90611848613a9d565b82915b808310611856578380f35b6118618382846135dd565b359261186b613a9d565b838552600960205260ff600160408720015460a81c1615611b9f578385526009602052604085206001015460a01c60ff16156118b45760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611b8d576118e9815f5260096020526001600160a01b0360405f205416331490565b15611b77576118f7816137dc565b90808652600960205261190f6002604088200161361f565b916001600160801b038351166001600160801b0382161015611b6457818752600960205260ff604088205460f01c1615611b515790611966826001600160801b036020818796818d99511603169501511690613364565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611b2c575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a906001600160a01b03600160408d2001541694611a688b858861430d565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611ad4575b505050505050600101919061184b565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b17575b80808080611ac4565b81611b21916132ee565b61099957835f611b0e565b818552600960205260016040862001600160a01b60ff60a01b198254161790556119c7565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590611bcf613a9d565b818152600960205260ff600160408320015460a81c16156106bd57611bf3826138bd565b6005811015611d925760048103611c175750602491634a5541ef60e01b8252600452fd5b60038103611c32575060249163fe19f19f60e01b8252600452fd5b600214611d8057611c57825f5260096020526001600160a01b0360405f205416331490565b15611d6a57818152600960205260ff604082205460f01c1615611d5857818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611cfd575050f35b813b15611d545782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611d435750f35b81611d4d916132ee565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b038116809103610fc3576001600160a01b03825416338103611e83575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e6f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff9352600a8452205416604051908152f35b50346104d65760203660031901126104d657611f1a6131b4565b9080546001600160a01b038116338103611e8357506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b03611f946131b4565b168015611fb1578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020611ffc6004356137a9565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d6576004359061202b613601565b50818152600960205260ff600160408320015460a81c16156106bd57816060928252600960205264ffffffffff6040818185205460a01c1693838152600a6020528282822054169381526009602052205460c81c16906040519261208e8461327c565b8352602083015260408201526120c6604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b50346104d6576101603660031901126104d6576120e3613a9d565b604051906120f08261324b565b6120f86131b4565b82526121026131ca565b602083015261210f61332c565b60408301526064356001600160a01b0381168103610fc35760608301526084358015158103610fc357608083015260a4358015158103610fc35760a083015260603660c31901126104d6576040516121668161327c565b60c43564ffffffffff8116810361099557815260e43564ffffffffff811681036109955760208201526101043564ffffffffff8116810361099557604082015260c08301526040610123193601126104d657604051906121c5826132d2565b61012435906001600160a01b03821682036104d65760206111de8585858152610144358482015260e0820152613bed565b50346104d65760403660031901126104d65760043567ffffffffffffffff8111610fc35761222890369060040161321a565b9060243567ffffffffffffffff81116109995761224990369060040161321a565b612251613a9d565b80840361267f57845b848110612265578580f35b6122708186866135dd565b3561227c8287876135dd565b35875260036020526001600160a01b036040882054169061229e8385876135dd565b356001600160801b03811680820361267b576122b8613a9d565b828a52600960205260ff600160408c20015460a81c161561266957828a52600960205260ff600160408c20015460a01c1661265657831561264357801561263057828a5260036020526001600160a01b0360408b205416908185141580612620575b612605576001600160801b0361232f856142e7565b168082116125ea5750908a91848352600960205280600260406001600160a01b03818720541695888152600960205220015460801c016001600160801b0381116125d657906123ad86959493928e989789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b84875260096020526123c46002604089200161361f565b6001600160801b036123e88160208401511692826040818351169201511690613364565b16111561259a575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461243a81868861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580612590575b612525575b81331415908161251a575b8161250f575b5061249e575b505050505060010161225a565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16124fa575b808080612491565b81612504916132ee565b61055e57855f6124f2565b90508114155f61248b565b823b15159150612485565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af161257b575b505061247a565b81612585916132ee565b61055e57855f612574565b50803b1515612475565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556123f0565b60248d634e487b7160e01b81526011600452fd5b8b906064928663287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061262a84613af7565b1561231a565b60248a8463d2aabcd960e01b8252600452fd5b60248a84630ff7ee2d60e31b8252600452fd5b60248a84634a5541ef60e01b8252600452fd5b60248a8462b8e7e760e51b8252600452fd5b8980fd5b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d783613b69565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5780612726836138bd565b926005841015611d9257600260209403612747575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061273b565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d6576004356127a5613a9d565b808252600960205260ff600160408420015460a81c161561107b57808252600960205260ff600160408420015460a01c161561293a576127e481613af7565b156129245780825260036020526001600160a01b0360408320541615158061291d575b80612900575b6128ee577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b0360408320541680159081156128b7575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506128a5575080f35b637e27328960e01b8252600452602490fd5b6128d6835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561285b565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c161561280d565b5081612807565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d657610fc0612977366131e0565b90604051926129876020856132ee565b858452613665565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612c6d576020366003190112612c6d57600435906129ff613a9d565b815f52600960205260ff600160405f20015460a81c1615612ce457815f52600960205260ff600160405f20015460a01c165f14612a495750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612cd257612a7c815f5260096020526001600160a01b0360405f205416331490565b15612cbc57612a8a816137dc565b90805f526009602052612aa2600260405f200161361f565b916001600160801b038351166001600160801b0382161015612ca957815f52600960205260ff60405f205460f01c1615612c9657806001600160801b03602081612af6948188511603169501511690613364565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612c71575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612be16001600160a01b03600160405f2001541694611a688b858861430d565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612c18578580f35b813b15612c6d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c5a575b808080808580f35b612c6691505f906132ee565b5f80612c52565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612b40565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612c6d57612d0d612d07366131e0565b91613398565b005b34612c6d575f366003190112612c6d576020600754604051908152f35b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da457612d64906138bd565b6005811015612d90578060209115908115612d85575b506040519015158152f35b600191501482612d7a565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da4576020905f90805f526009835260ff60405f205460f01c1680612e4a575b612e18575b506001600160801b0360405191168152f35b612e449150805f5260098352612e3e6001600160801b03600260405f20015416916137dc565b90613364565b82612e06565b50805f526009835260ff600160405f20015460a01c1615612e01565b34612c6d576040366003190112612c6d57612e7f6131b4565b602435612e8b816137a9565b33151580612f58575b80612f25575b612ef95781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612e9a565b50336001600160a01b0382161415612e94565b34612c6d576020366003190112612c6d576020611ffc600435613342565b34612c6d575f366003190112612c6d576040515f6001548060011c90600181168015613073575b60208310811461305f5782855290811561303b5750600114612fdd575b61091283611369818503826132ee565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061302157509091508101602001611369612fcd565b919260018160209254838588010152019101909291613009565b60ff191660208086019190915291151560051b840190910191506113699050612fcd565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612fb0565b34612c6d575f366003190112612c6d57602060405167016345785d8a00008152f35b34612c6d576020366003190112612c6d57600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612c6d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115613144575b811561311a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613113565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061310c565b5f5b83811061317f5750505f910152565b8181015183820152602001613170565b906020916131a88151809281855285808601910161316e565b601f01601f1916010190565b600435906001600160a01b0382168203612c6d57565b602435906001600160a01b0382168203612c6d57565b6060906003190112612c6d576004356001600160a01b0381168103612c6d57906024356001600160a01b0381168103612c6d579060443590565b9181601f84011215612c6d5782359167ffffffffffffffff8311612c6d576020808501948460051b010111612c6d57565b610100810190811067ffffffffffffffff82111761326857604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761326857604052565b610180810190811067ffffffffffffffff82111761326857604052565b610140810190811067ffffffffffffffff82111761326857604052565b6040810190811067ffffffffffffffff82111761326857604052565b90601f8019910116810190811067ffffffffffffffff82111761326857604052565b67ffffffffffffffff811161326857601f01601f191660200190565b604435906001600160801b0382168203612c6d57565b61334b816137a9565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161338457565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156135ca57815f5260036020526001600160a01b0360405f2054161515806135c2575b806135a5575b613592577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134dd575b6001600160a01b039350856134a6575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361348e57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6134c5825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561342d565b919290508061353b575b156134f45782829161341d565b828461350c57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613569575b806134e75750825f526005602052336001600160a01b0360405f205416146134e7565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613546565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c16156133cd565b5060016133c7565b633250574960e11b5f525f60045260245ffd5b91908110156135ed5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061360e8261327c565b5f6040838281528260208201520152565b9060405161362c8161327c565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff81168103612c6d5790565b90613671838284613398565b803b61367e575b50505050565b6020916136c46001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061318f565b03815f865af15f918161374c575b5061370057506136e06142b8565b805190816136fb5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361373a57505f808080613678565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116137a1575b81613768602093836132ee565b81010312612c6d57517fffffffff0000000000000000000000000000000000000000000000000000000081168103612c6d57905f6136d2565b3d915061375b565b805f5260036020526001600160a01b0360405f2054169081156137ca575090565b637e27328960e01b5f5260045260245ffd5b805f52600a60205264ffffffffff60405f205416815f52600960205264ffffffffff60405f205460a01c1690421080156138b4575b6138ae57815f52600960205264ffffffffff60405f205460c81c1690814210156138915780613843920390420361449b565b815f5260096020526138666001600160801b03600260405f200154168092614587565b90811161387b576001600160801b0391501690565b505f526009602052600260405f20015460801c90565b50505f5260096020526001600160801b03600260405f2001541690565b50505f90565b50428111613811565b805f52600960205260ff600160405f20015460a01c165f146138df5750600490565b805f52600960205260405f205460f81c61394b57805f52600960205264ffffffffff60405f205460a01c16421061394657613919816137dc565b905f5260096020526001600160801b0380600260405f200154169116105f1461394157600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a8b575b80613a6e575b613a5c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a25575b1680613a0d575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556139c9565b613a44835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556139c2565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613976565b506001600160a01b0382161515613970565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613acf57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b3d575b508115613b24575090565b90506001600160a01b03613b383392613342565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b19565b805f526009602052613b80600260405f200161361f565b90805f52600960205260ff600160405f20015460a01c165f14613bae5750602001516001600160801b031690565b90815f52600960205260405f205460f81c613bd05750613bcd906137dc565b90565b613bcd91506001600160801b036040818351169201511690613364565b90613c0e6001600160801b03604084015116602060e0850151015190614364565b916001600160801b0383511660c082015190156142905764ffffffffff81511615614268576020810164ffffffffff815116806141dc575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141ae57505064ffffffffff80421691511690818110156141805750506007549280516001600160801b03169160405192613c9e8461327c565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d04896132b5565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600960205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f8491906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614160575b50600185016007556001600160a01b0360208201511680156135ca57613ff2866001600160a01b0392613951565b166141345761401d6001600160a01b036060830151166001600160801b038451169030903390614441565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614105575b506140fc6001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b61412e906001600160a01b036060880151166001600160a01b0360e08901515116903390614441565b5f614058565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600a60205260405f209064ffffffffff198254161790555f613fc4565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561423a57505064ffffffffff90511664ffffffffff60408301511690818110613c46577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d156142e2573d906142c982613310565b916142d760405193846132ee565b82523d5f602084013e565b606090565b613bcd906142f481613b69565b905f526009602052600260405f20015460801c90613364565b614362926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261435d6064836132ee565b614635565b565b919091604051614373816132d2565b5f81525f6020820152926001600160801b0382169081156144245767016345785d8a000081116143ed576143af6001600160801b039183614587565b16602085019181835211156143d9576001600160801b0391826143d492511690613364565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614435816132d2565b5f81525f602082015290565b9091926001600160a01b036143629481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261435d6084836132ee565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614566578184101561452c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614573570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461462457670de0b6b3a76400008210156145f4577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361465e93169360208151910182865af16146576142b8565b90836146c3565b805190811515918261469f575b50506146745750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612c6d5760200151801590811503612c6d575f8061466b565b9061470057508051156146d857805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614746575b614711575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561470956fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c034620003c3576001600160401b0390601f601f1962004de93881900383810183168501919086831186841017620002e557808692606094604052833981010312620003c35782516001600160a01b038082169590929091869003620003c35760209485810151938416809403620003c357604001519362000081620003c7565b95601e87527f5361626c696572205632204c6f636b7570205472616e63686564204e4654000081880152620000b5620003c7565b9060118252705341422d56322d4c4f434b55502d54524160781b81830152306080528751858111620002e5576001988954908a82811c92168015620003b8575b84831014620002c657818684931162000365575b50839086831160011462000305575f92620002f9575b50505f19600383901b1c191690891b1788555b8151948511620002e557600254938885811c95168015620002da575b82861014620002c65784848796116200026c575b5081938511600114620002065750505f92620001fa575b50505f19600383901b1c191690841b176002555b60018060a01b031984815f5416175f556008541617600855604051925f7fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600755614a019081620003e8823960805181613e09015260a051818181612f120152613eaf0152f35b015190505f8062000179565b8895939291931660025f52835f20935f905b82821062000252575050841162000239575b505050811b016002556200018d565b01515f1960f88460031b161c191690555f80806200022a565b8484015186558a9790950194938401939081019062000218565b90919293945060025f52825f208580880160051c820192858910620002bc575b9188978c9297969594930160051c01915b828110620002ad57505062000162565b5f81558897508b91016200029d565b925081926200028c565b634e487b7160e01b5f52602260045260245ffd5b94607f16946200014e565b634e487b7160e01b5f52604160045260245ffd5b015190505f806200011f565b90878c941691845f52855f20925f5b878282106200034e575050841162000335575b505050811b01885562000132565b01515f1960f88460031b161c191690555f808062000327565b8385015186558f9790950194938401930162000314565b9091508a5f52835f208680850160051c820192868610620003ae575b918d91869594930160051c01915b8281106200039f57505062000109565b5f81558594508d91016200038f565b9250819262000381565b91607f1691620000f5565b5f80fd5b60408051919082016001600160401b03811183821017620002e55760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a7146132b257508063027b67441461329057806306fdde031461319a578063081812fc1461317c578063095ea7b3146130835780631400ecec14612fe35780631c1cdd4c14612f6b5780631e99d56914612f4e57806323b872dd14612f355780632fe4304114612efb57806332fbe22b14612da657806340e58ee514612aea578063425d30dd14612a9957806342842e0e14612a5f57806342966c6814612896578063442675701461286f5780634857501f146127f95780634869e12d146127be5780634cc55e11146122fb57806357404b12146122645780636352211e146122345780636d0cee751461223457806370a08231146121c457806375829def146121315780637cad6cd1146120385780637de6b1db14611e135780637f5799f914611db85780638659c27014611a5f578063894e9a0d146116d5578063897f362b146114285780638f69b9931461138d5780639067b6771461133d57806395d89b411461122e578063a22cb46514611173578063a80fc07114611121578063ad35efd4146110bf578063b25645691461106e578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5d578063bc2be1be14610f0d578063c156a11d14610a5e578063c87b56dd14610942578063d4dbd20b146108f0578063d511609f146108a4578063d975dfed14610858578063e985e9c514610805578063ea5ead191461070b578063eac8f5b8146106b9578063f590c17614610657578063f851a440146106315763fdd46d601461025a575f80fd5b3461062e57606036600319011261062e57600435906102776133dd565b91604435926001600160801b038085169182860361062a57610297613dff565b83855260099560209387855260ff600160408920015460a81c16156106135785875287855260ff600160408920015460a01c166105fb576001600160a01b039081841680156105e35781156105cb57878952600387528260408a2054169283821415806105bb575b6105975761030c89614646565b8781168411610565575097899a888b999a83809d5282825260408b209988828c54169b6002015460801c906103409161466c565b858d5284845260408d20600201908282549160801b6fffffffffffffffffffffffffffffffff1916911617815561037690613968565b90808483015116918180825116916040015116610392916135c2565b161115927f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d93610536575b848c528252600160408c20015416946103d7818a886147ca565b604051908152a4803314158061052c575b6104be575b8333141590816104b3575b816104a8575b50610432575b837ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78688604051908152a180f35b823b156104a457604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af161048c575b8080610404565b610495906134e5565b6104a057825f610485565b8280fd5b8380fd5b90508314155f6103fe565b843b151591506103f8565b803b1561052857604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af1610514575b50506103ed565b61051d906134e5565b61052857845f61050d565b8480fd5b50803b15156103e8565b848c5280835260408c2060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556103bd565b60405163287ecaef60e21b8152600481018b90526001600160801b038781166024830152919091166044820152606490fd5b606489836040519163b34359d360e01b835260048301523360248301526044820152fd5b506105c589614539565b156102ff565b6024886040519063d2aabcd960e01b82526004820152fd5b60248860405190630ff7ee2d60e31b82526004820152fd5b60248660405190634a5541ef60e01b82526004820152fd5b6024866040519062b8e7e760e51b82526004820152fd5b5f80fd5b80fd5b503461062e578060031936011261062e576001600160a01b036020915416604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257816040916020935260098352205460f81c6040519015158152f35b6024906040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760016040836001600160a01b0393602095526009855220015416604051908152f35b503461062e57604036600319011261062e57600435906107296133dd565b9161073381614646565b9261073c613dff565b81835260099360209185835260ff600160408720015460a81c16156107ee5783855285835260ff600160408720015460a01c166107d6576001600160a01b03918282169283156107be576001600160801b03938483169081156105cb57878952600387528260408a2054169283821415806105bb576105975761030c89614646565b60248660405190630ff7ee2d60e31b82526004820152fd5b60248460405190634a5541ef60e01b82526004820152fd5b6024846040519062b8e7e760e51b82526004820152fd5b503461062e57604036600319011261062e5761081f6133c7565b60406108296133dd565b926001600160a01b03809316815260066020522091165f52602052602060ff60405f2054166040519015158152f35b503461062e57602036600319011261062e5760ff6001604060043593848152600960205220015460a81c16156106a257610893602091614646565b6001600160801b0360405191168152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257604082600292602094526009845220015460801c604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760036040836001600160801b0393602095526009855220015416604051908152f35b503461062e57602080600319360112610a4e5760043561096181613b24565b50826001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa928315610a525780936109d1575b50506109cd6040519282849384528301906133a2565b0390f35b909192503d8082843e6109e4818461354e565b8201918381840312610a4e5780519067ffffffffffffffff82116104a0570182601f82011215610a4e57805191610a1a83613570565b93610a28604051958661354e565b83855285848401011161062e575090610a4691848085019101613381565b905f806109b7565b5080fd5b604051903d90823e3d90fd5b503461062e57604036600319011261062e57600435610a7b6133dd565b610a83613dff565b81835260099060209082825260ff600160408720015460a81c16156107ee57838552600382526001600160a01b03918260408720541693843303610eee57610aca86614646565b906001600160801b039081831680158015610b6a575b50505050505081811615610b525783610af891613cc4565b90811680610b185760248460405190637e27328960e01b82526004820152fd5b8203610b22578380f35b6040516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b60248560405190633250574960e11b82526004820152fd5b610b72613dff565b898b5282865260ff600160408d20015460a81c1615610ed757898b5282865260ff600160408d20015460a01c16610ebf578815610ea757610e8f57888a52600385528660408b205416918289141580610e7f575b610e5b57610bd38a614646565b8481168311610e295750908a949392918a86528087526040862093610c38610c068760028d89541698015460801c61466c565b8d8952838a52600260408a200190836fffffffffffffffffffffffffffffffff1983549260801b169116178155613968565b90610c54818a84015116928260408183511692015116906135c2565b161115610dfa575b8a86528652888a7f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d888b600160408b2001541694610c9b8186886147ca565b604051908152a48033141580610df0575b610d86575b813314159081610d7b575b81610d70575b50610cff575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790604051868152a15f8080808080610ae0565b803b156104a057604051636fd110e960e01b8152600481018990523360248201526001600160a01b03881660448201526001600160801b0392909216606483015282908290608490829084905af1610d58575b80610cc8565b610d61906134e5565b610d6c57855f610d52565b8580fd5b90508114155f610cc2565b823b15159150610cbc565b803b156104a457604051636fd110e960e01b8152600481018a90523360248201526001600160a01b03891660448201526001600160801b03841660648201528490818160848183875af1610ddc575b5050610cb1565b610de5906134e5565b6104a457835f610dd5565b50803b1515610cac565b8a86528087526040862060018101600160a01b60ff60a01b1982541617905560ff60f01b198154169055610c5c565b60405163287ecaef60e21b8152600481018c90526001600160801b038781166024830152919091166044820152606490fd5b60648a8a6040519163b34359d360e01b835260048301523360248301526044820152fd5b50610e898a614539565b15610bc6565b6024896040519063d2aabcd960e01b82526004820152fd5b60248a60405190630ff7ee2d60e31b82526004820152fd5b60248a60405190634a5541ef60e01b82526004820152fd5b60248a6040519062b8e7e760e51b82526004820152fd5b60405163216caf0d60e01b815260048101879052336024820152604490fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760408264ffffffffff926020945260098452205460a01c16604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576040826001600160a01b03926020945260098452205416604051908152f35b503461062e57602036600319011261062e5760ff6001604060209360043581526009855220015460a81c166040519015158152f35b503461062e57608036600319011261062e57610ffb6133c7565b6110036133dd565b906064359067ffffffffffffffff82116104a457366023830112156104a4578160040135928461103285613570565b93611040604051958661354e565b8585523660248783010111610a4e578561106b966024602093018388013785010152604435916139bd565b80f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257600160408360ff93602095526009855220015460b01c166040519015158152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576110f890613c44565b60405190600581101561110d57602092508152f35b602483634e487b7160e01b81526021600452fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760026040836001600160801b0393602095526009855220015416604051908152f35b503461062e57604036600319011261062e5761118d6133c7565b6024359081151580920361062a576001600160a01b03169081156111fd57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602482604051907f5b08ba180000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e578060031936011261062e5760405190806002549160018360011c9260018516948515611333575b602095868610811461131f578588528794939291879082156112fd5750506001146112a3575b505061128f9250038361354e565b6109cd6040519282849384528301906133a2565b90859250600282527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8583106112e557505061128f93508201015f80611281565b805483890185015287945086939092019181016112cd565b925093505061128f94915060ff191682840152151560051b8201015f80611281565b602483634e487b7160e01b81526022600452fd5b93607f169361125b565b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a25760408264ffffffffff926020945260098452205460c81c16604051908152f35b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a2576113c690613c44565b9060058210159081611407576002831491821561141b575b82156113f2575b6020836040519015158152f35b90915061140757506004602091145f806113e5565b80634e487b7160e01b602492526021600452fd5b506003831491505f6113de565b503461062e576020906003198281360112610a4e576004359167ffffffffffffffff91828411610a4e5761012084360391820112610a4e57611468613dff565b60c48401359060221901811215610a4e5783016004810135928311610a4e5760248101908360061b80360383136104a4576024906114a586613838565b956114b3604051978861354e565b8652878601920101913683116104a457905b868383106116bd57505050508151906114dd82613838565b926114eb604051948561354e565b828452601f196114fa84613838565b0186835b82811061169b5750505064ffffffffff804216936001600160801b03928361152582613b45565b51511683808b61153485613b45565b5101511688011660405191611548836134f9565b82528a82015261155788613b45565b5261156187613b45565b5060019260015b8381106116335750505050506115808560040161399c565b9161158d6024870161399c565b9161159a604488016138d9565b6064880135926001600160a01b039081851680950361062e5750928895926115eb98959261162098956115d2608461162b9d016139b0565b94816115e060a48c016139b0565b976040519d8e6134c8565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613886565b610100820152613e5b565b604051908152f35b8089838d8180826116578d6116498e9a8d613b52565b515116965f19890190613b52565b5101511691611666868a613b52565b51015116011660405191611679836134f9565b82528d820152611689828c613b52565b52611694818b613b52565b5001611568565b6040516116a7816134f9565b5f81525f838201528282890101520187906114fe565b6040916116ca3685613850565b8152019101906114c5565b503461062e57602036600319011261062e5760606101606040516116f881613515565b83815283602082015283604082015283838201528360808201528360a08201528360c08201528360e0820152836101008201528361012082015260405161173e81613532565b84815284602082015284604082015261014082015201526004358152600960205260ff600160408320015460a81c1615611a475760043581526009602052604081209060405191610140830183811067ffffffffffffffff821117611a335761182f9160029160405280546001600160a01b038116865264ffffffffff8160a01c16602087015264ffffffffff8160c81c16604087015260ff8160f01c161515606087015260f81c1515608086015260ff60018201546001600160a01b03811660a0880152818160a01c16151560c0880152818160a81c16151560e088015260b01c16151561010086015201613968565b610120830152611840600435613c44565b6005811015611a1f57610160926118eb9260026119279314611a14575b610120820151906001600160a01b0360a08401511664ffffffffff6040850151169060608501511515908560c081015115159260e0820151151594610100830151151596600435815260036020526001600160a01b036040822054166080604064ffffffffff60206001600160a01b038951169801511693600a602052209b01511515946040519d8e613515565b8d5260208d015260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526138ed565b828201526109cd604051928392602084526001600160a01b0381511660208501526001600160a01b03602082015116604085015264ffffffffff604082015116606085015264ffffffffff60608201511660808501526080810151151560a085015260a0810151151560c08501526001600160a01b0360c08201511660e085015260e081015115156101008501526101008101511515610120850152610120810151151561014085015261014081015160406001600160801b03918281511685880152826020820151166101808801520151166101a085015201516101c0808401526101e083019061346d565b80606083015261185d565b602482634e487b7160e01b81526021600452fd5b634e487b7160e01b5f52604160045260245ffd5b602460405162b8e7e760e51b81526004356004820152fd5b503461062e57602080600319360112610a4e5760043567ffffffffffffffff81116104a057611a9290369060040161343c565b9190611a9c613dff565b83925b808410611aaa578480f35b611ab58482846138b5565b3593611abf613dff565b848652600980855260ff600191818360408b20015460a81c1615611da157878952808752604089208381015460a01c831615611b0d5760248960405190634a5541ef60e01b82526004820152fd5b9790919293949596975460f81c611d8957611b3c815f5260096020526001600160a01b0360405f205416331490565b15611d6957611b4a81613b66565b93818a52828952611b60600260408c2001613968565b946001600160801b0394858751168683161015611d5157838c52848b5260408c205460f01c1615611d3957918493918a611bac85878f9a99808c9986928d511603169a015116906135c2565b918386528482527f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611c8560408089209384549a600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d1617865587169a8b15611d20575b60038096018d6fffffffffffffffffffffffffffffffff198254161790556001600160a01b0392838092169b8c9789522054169889965260408d2001541694611c5d8b85886147ca565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce78a604051838152a1813b611cc9575b505050505050600101929190611a9f565b813b15610d6c57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d0c575b80808080611cb8565b611d15906134e5565b61052857845f611d03565b818601600160a01b60ff60a01b19825416179055611c13565b602483604051906339c6dc7360e21b82526004820152fd5b602484604051906322cad1af60e11b82526004820152fd5b60405163216caf0d60e01b81526004810191909152336024820152604490fd5b6024906040519063fe19f19f60e01b82526004820152fd5b6024886040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257604082611dff926109cd9452600a602052206138ed565b60405191829160208352602083019061346d565b503461062e57602080600319360112610a4e5760043590611e32613dff565b8183526009815260ff600160408520015460a81c161561202157611e5582613c44565b600581101561200d5760048103611e7e5760248360405190634a5541ef60e01b82526004820152fd5b60038103611e9e576024836040519063fe19f19f60e01b82526004820152fd5b600214611ff557611ec3825f5260096020526001600160a01b0360405f205416331490565b15611fd6578183526009815260ff604084205460f01c1615611fbe57818352600981526040832060ff60f01b19815416905582604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8380a2600383526001600160a01b03604083205416803b611f66575b5050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791604051908152a180f35b803b156104a057816024818580947f450154640000000000000000000000000000000000000000000000000000000083528960048401525af1611faa575b80611f37565b611fb3906134e5565b6104a057825f611fa4565b602482604051906339c6dc7360e21b82526004820152fd5b60405163216caf0d60e01b815260048101839052336024820152604490fd5b602482604051906322cad1af60e11b82526004820152fd5b602484634e487b7160e01b81526021600452fd5b6024826040519062b8e7e760e51b82526004820152fd5b503461062e57602036600319011261062e576004356001600160a01b03908181168091036104a05781835416338103612108575060085491816001600160a01b03198416176008556040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120f45760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b6040516331b339a960e21b81526001600160a01b03919091166004820152336024820152604490fd5b503461062e57602036600319011261062e5761214b6133c7565b9080546001600160a01b038082169333850361219d576001600160a01b03199394501691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b6040516331b339a960e21b81526001600160a01b0386166004820152336024820152604490fd5b503461062e57602036600319011261062e576001600160a01b036121e66133c7565b168015612203578160409160209352600483522054604051908152f35b602482604051907f89c62b640000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e57602036600319011261062e576020612253600435613b24565b6001600160a01b0360405191168152f35b503461062e57602036600319011261062e576004355f6020604051612288816134f9565b8281520152808252600960205260ff600160408420015460a81c16156106a257604082819281526009602052205464ffffffffff8251916122c8836134f9565b818160a01c16835260c81c1660208201526122f9825180926020908164ffffffffff91828151168552015116910152565bf35b503461062e57604036600319011261062e5767ffffffffffffffff6004358181116104a05761232e90369060040161343c565b909160249081359081116105285761234a90369060040161343c565b612355929192613dff565b80840361278857855b848110612369578680f35b6123748186886138b5565b35906123818187896138b5565b35885260036020526001600160a01b036040892054166123aa6123a58386896138b5565b6138d9565b906123b3613dff565b838a52600960205260ff600160408c20015460a81c161561277257838a52600960205260ff600160408c20015460a01c1661275b578015612744576001600160801b0382161561272d57838a5260036020526001600160a01b0360408b20541691828214158061271d575b6126f95761242b85614646565b6001600160801b0381166001600160801b038316116126c95750908a9291858452600960205260408420926124b16001600160a01b03855416946002809101546001600160801b036fffffffffffffffffffffffffffffffff1961249387608094851c61466c565b938c8b52600960205260408b2001938454931b169116178155613968565b6001600160801b036124d581602084015116928260408183511692015116906135c2565b161115612698575b86855260096020526001600160a01b0360016040872001541661250a6001600160801b03841685836147ca565b83887f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206040516001600160801b0388168152a4803314158061268e575b612624575b833314159081612619575b8161260e575b5061259c575b505050507ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020600193604051908152a10161235e565b823b156104a457604051636fd110e960e01b8152600481018790523360248201526001600160a01b039290921660448301526001600160801b031660648201529082908290608490829084905af16125f6575b8080612565565b6125ff906134e5565b61260a57875f6125ef565b8780fd5b90508314155f61255f565b843b15159150612559565b803b1561052857604051636fd110e960e01b8152600481018890523360248201526001600160a01b03841660448201526001600160801b03831660648201528590818160848183875af161267a575b505061254e565b612683906134e5565b61052857845f612673565b50803b1515612549565b86855260096020526040852060018101600160a01b60ff60a01b1982541617905560ff60f01b1981541690556124dd565b60405163287ecaef60e21b8152600481018790526001600160801b03928316602482015291166044820152606490fd5b60648583896040519263b34359d360e01b8452600484015233908301526044820152fd5b5061272785614539565b1561241e565b85846040519063d2aabcd960e01b82526004820152fd5b858460405190630ff7ee2d60e31b82526004820152fd5b858460405190634a5541ef60e01b82526004820152fd5b85846040519062b8e7e760e51b82526004820152fd5b8390604492604051927faec934400000000000000000000000000000000000000000000000000000000084526004840152820152fd5b503461062e57602036600319011261062e5760ff6001604060043593848152600960205220015460a81c16156106a25761089360209161459e565b503461062e57602036600319011261062e5760043590818152600960205260ff600160408320015460a81c1615612021578061283483613c44565b926005841015611a1f57600260209403612855575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80612849565b503461062e578060031936011261062e5760206001600160a01b0360085416604051908152f35b503461062e57602080600319360112610a4e57600435906128b5613dff565b8183526009815260ff600160408520015460a81c1615612021578183526009815260ff600160408520015460a01c1615612a2e576128f282614539565b15611fd657815f52600381526001600160a01b038060405f205416151580612a27575b80612a0e575b6129f6577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790835f526003835260405f2054169182159283156129c0575b845f526003825260405f206001600160a01b03198154169055845f604051927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4848152a16129a8575080f35b60249060405190637e27328960e01b82526004820152fd5b6129df855f52600560205260405f206001600160a01b03198154169055565b805f526004825260405f205f198154019055612959565b60248360405190630da9b01360e01b82526004820152fd5b506009825260ff600160405f20015460b01c161561291b565b505f612915565b602482604051907f817cd6390000000000000000000000000000000000000000000000000000000082526004820152fd5b503461062e57612a6e36613407565b60405191602083019383851067ffffffffffffffff861117611a335761106b946040528584526139bd565b503461062e57602036600319011261062e57600435808252600960205260ff600160408420015460a81c16156106a257600160408360ff93602095526009855220015460a01c166040519015158152f35b503461062a5760208060031936011261062a5760043590612b09613dff565b815f52600980825260ff600160405f20015460a81c1615612d8f57825f5280825260405f2060ff600182015460a01c165f14612b575760248460405190634a5541ef60e01b82526004820152fd5b5460f81c612d7757612b7d835f5260096020526001600160a01b0360405f205416331490565b15612d5857612b8b83613b66565b835f52818352612ba0600260405f2001613968565b936001600160801b0391828651168382161015611ff557815f5283855260ff60405f205460f01c1615611fbe57612c06818487817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795818c5116031699015116906135c2565b94825f5284815260405f20956003875495600160f81b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff88161789558216978815612d3e575b01886fffffffffffffffffffffffffffffffff198254161790556001600160a01b038095169560038352867f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa508760405f2054169788938652600160405f2001541693612cb78c84876147ca565b604080518981526001600160801b038e811660208301529290921690820152606090a4604051838152a1813b612ceb578580f35b813b1561062a575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d2d575b808080808580f35b612d3791506134e5565b5f80612d25565b60018101600160a01b60ff60a01b19825416179055612c4a565b60405163216caf0d60e01b815260048101849052336024820152604490fd5b6024836040519063fe19f19f60e01b82526004820152fd5b6024836040519062b8e7e760e51b82526004820152fd5b3461062a576003196020368201811361062a576004359067ffffffffffffffff9283831161062a5761014090833603011261062a57612de3613dff565b60405192612df0846134c8565b612dfc836004016133f3565b8452612e0a602484016133f3565b6020850152612e1b6044840161358c565b604085015260648301356001600160a01b038116810361062a576060850152612e46608484016134bb565b6080850152612e5760a484016134bb565b60a0850152612e6860c48401613826565b60c085015260e483013590811161062a5782013660238201121561062a57600481013591612e9583613838565b92612ea3604051948561354e565b8084526024602085019160061b8401019236841161062a57602401905b838210612ee257602061162b88611620898960e0840152610104369101613886565b82604091612ef03685613850565b815201910190612ec0565b3461062a575f36600319011261062a5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b3461062a57612f4c612f4636613407565b916135ef565b005b3461062a575f36600319011261062a576020600754604051908152f35b3461062a57602036600319011261062a57600435805f52600960205260ff600160405f20015460a81c16156106a257612fa390613c44565b6005811015612fcf578060209115908115612fc4575b506040519015158152f35b600191501482612fb9565b634e487b7160e01b5f52602160045260245ffd5b3461062a57602036600319011261062a57600435805f52600960205260ff600160405f20015460a81c16156106a2576020905f90805f526009835260405f2060ff815460f01c1680613071575b613048575b50506001600160801b0360405191168152f35b61306a92506001600160801b0360026130649201541691613b66565b906135c2565b8280613035565b5060ff600182015460a01c1615613030565b3461062a57604036600319011261062a5761309c6133c7565b6024356130a881613b24565b33151580613169575b8061313f575b61310f5781906001600160a01b03809416938491167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f52600560205260405f20906001600160a01b03198254161790555f80f35b60246040517fa9fbf51f000000000000000000000000000000000000000000000000000000008152336004820152fd5b506001600160a01b0381165f52600660205260405f20335f5260205260ff60405f205416156130b7565b50336001600160a01b03821614156130b1565b3461062a57602036600319011261062a5760206122536004356135a0565b3461062a575f36600319011261062a576040515f600190600154918260011c9160018416918215613286575b60209485851084146132725785879486865291825f146132525750506001146131f7575b5061128f9250038361354e565b84915060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f915b85831061323a57505061128f9350820101856131ea565b80548389018501528794508693909201918101613223565b60ff19168582015261128f95151560051b85010192508791506131ea9050565b634e487b7160e01b5f52602260045260245ffd5b92607f16926131c6565b3461062a575f36600319011261062a57602060405167016345785d8a00008152f35b3461062a57602036600319011261062a57600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361062a57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115613357575b811561332d575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613326565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061331f565b5f5b8381106133925750505f910152565b8181015183820152602001613383565b906020916133bb81518092818552858086019101613381565b601f01601f1916010190565b600435906001600160a01b038216820361062a57565b602435906001600160a01b038216820361062a57565b35906001600160a01b038216820361062a57565b606090600319011261062a576001600160a01b0390600435828116810361062a5791602435908116810361062a579060443590565b9181601f8401121561062a5782359167ffffffffffffffff831161062a576020808501948460051b01011161062a57565b9081518082526020808093019301915f5b82811061348c575050505090565b835180516001600160801b0316865282015164ffffffffff16858301526040909401939281019260010161347e565b3590811515820361062a57565b610120810190811067ffffffffffffffff821117611a3357604052565b67ffffffffffffffff8111611a3357604052565b6040810190811067ffffffffffffffff821117611a3357604052565b610180810190811067ffffffffffffffff821117611a3357604052565b6060810190811067ffffffffffffffff821117611a3357604052565b90601f8019910116810190811067ffffffffffffffff821117611a3357604052565b67ffffffffffffffff8111611a3357601f01601f191660200190565b35906001600160801b038216820361062a57565b6135a981613b24565b505f5260056020526001600160a01b0360405f20541690565b6001600160801b0391821690821603919082116135db57565b634e487b7160e01b5f52601160045260245ffd5b906001600160a01b0380911690811561380f57835f526020906003825260409181835f205416151580613807575b806137ef575b6137d857855f526003815281835f2054169333151580613731575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce791856136fc575b805f5260048252845f2060018154019055875f5260038252845f20816001600160a01b031982541617905587855191877fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4878152a1831682036136ce5750505050565b516364283d7b60e01b81526001600160a01b0392831660048201526024810193909352166044820152606490fd5b61371b885f52600560205260405f206001600160a01b03198154169055565b855f5260048252845f205f198154019055613668565b80613797575b15613742575f61363e565b83878661375f576024915190637e27328960e01b82526004820152fd5b90517f177e802f0000000000000000000000000000000000000000000000000000000081523360048201526024810191909152604490fd5b5033851480156137bc575b806137375750865f52600582523383855f20541614613737565b50845f5260068252835f20335f52825260ff845f2054166137a2565b602486845190630da9b01360e01b82526004820152fd5b506009815260ff6001845f20015460b01c1615613623565b50600161361d565b6024604051633250574960e11b81525f6004820152fd5b359064ffffffffff8216820361062a57565b67ffffffffffffffff8111611a335760051b60200190565b919082604091031261062a57604051613868816134f9565b60206138818183956138798161358c565b855201613826565b910152565b919082604091031261062a5760405161389e816134f9565b60208082946138ac816133f3565b84520135910152565b91908110156138c55760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361062a5790565b9081546138f981613838565b9260409361390a604051918261354e565b82815280946020809201925f5260205f20905f935b85851061392e57505050505050565b6001848192845161393e816134f9565b64ffffffffff87546001600160801b038116835260801c168382015281520193019401939161391f565b9060405161397581613532565b6040819360018154916001600160801b0392838116865260801c6020860152015416910152565b356001600160a01b038116810361062a5790565b35801515810361062a5790565b919290926139cc8185856135ef565b833b6139d9575b50505050565b6020906001600160a01b0380951694613a3a60405194859384937f150b7a02000000000000000000000000000000000000000000000000000000009889865233600487015216602485015260448401526080606484015260848301906133a2565b03815f875af15f9181613ac7575b50613a7e5782613a56614617565b8051919082613a775760248260405190633250574960e11b82526004820152fd5b9050602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000001603613aaf57505f8080806139d3565b60249060405190633250574960e11b82526004820152fd5b9091506020813d602011613b1c575b81613ae36020938361354e565b8101031261062a57517fffffffff000000000000000000000000000000000000000000000000000000008116810361062a57905f613a48565b3d9150613ad6565b805f5260036020526001600160a01b0360405f2054169081156129a8575090565b8051156138c55760200190565b80518210156138c55760209160051b010190565b64ffffffffff80421691805f52602090600a602052613b8760405f206138ed565b9084846020613b9585613b45565b5101511611613c3b575f52600960205260405f208484825460c81c161115613c2657506001600160801b039081613bcb82613b45565b515116946001948594855b613be5575b5050505050505090565b8351871015613c2157828282613bfb8a88613b52565b5101511611613c21578585889981613c14849b89613b52565b5151160116980196613bd6565b613bdb565b600201546001600160801b0316949350505050565b50505050505f90565b805f52600960205260405f2060ff600182015460a01c165f14613c68575050600490565b805460f81c613cbd575460a01c64ffffffffff164210613cb857613c8b81613b66565b905f5260096020526001600160801b0380600260405f200154169116105f14613cb357600190565b600290565b505f90565b5050600390565b91815f526020600381526001600160a01b039360409085825f205416151580613df4575b80613ddc575b613dc5578480967ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795965f526003855280845f2054169283613d90575b169283613d7a575b815f5260038552805f20846001600160a01b03198254161790555192827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4948152a1565b835f5260048552805f2060018154019055613d33565b613daf835f52600560205260405f206001600160a01b03198154169055565b835f5260048652845f205f198154019055613d2b565b602485835190630da9b01360e01b82526004820152fd5b506009835260ff6001835f20015460b01c1615613cee565b508581161515613ce8565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e3157565b60046040517fa1c0d6e5000000000000000000000000000000000000000000000000000000008152fd5b90613e7d6001600160801b036040840151166020610100850151015190614687565b6001600160801b0381511660e084015164ffffffffff60c086015116821561450f5780156144e557815180156144bb577f0000000000000000000000000000000000000000000000000000000000000000811161448a575064ffffffffff6020613ee684613b45565b5101511681101561443357505f905f905f81515f905b8082106143a2575050505064ffffffffff421664ffffffffff82168110156143625750506001600160801b031680820361432b57505060075492835f52600960205260405f20916001600160801b0381511660028401906fffffffffffffffffffffffffffffffff198254161790556001600160a01b036060830151166001840154750100000000000000000000000000000000000000000060808501511515918654937fffffffffffffffffff0000ff000000000000000000000000000000000000000076ff0000000000000000000000000000000000000000000060a0890151151560b01b16921617171760018601556001600160a01b0384511678ffffffffff000000000000000000000000000000000000000060c086015160a01b169060e0860151937fff000000000000000000000000000000000000000000000000000000000000007eff0000000000000000000000000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140958951995f198b0190613b52565b51015160c81b169560f01b1691161717171784555f5b81811061428a575050600185016007556001600160a01b03602083015116801561380f576140e1866001600160a01b0392613cc4565b1661425a5761410c6001600160a01b036060840151166001600160801b038351169030903390614759565b6001600160801b036020820151168061422a575b507ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f807660206001600160a01b03845116926001600160a01b038286015116946001600160a01b036060820151169661421f61420060808401511515928c60a086015115156001600160a01b0361010060e089015194549864ffffffffff6040519a6141a98c6134f9565b818160a01c168c5260c81c168c8b015201515116956001600160801b036040519a8b9a610140958c5233828d01528281511660408d015201511660608a0152608089015260a08801528060c088015286019061346d565b9260e08501906020908164ffffffffff91828151168552015116910152565b6101208301520390a4565b614254906001600160a01b036060850151166001600160a01b036101008601515116903390614759565b5f614120565b60246040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152fd5b865f52600a60205260405f20906142a58160e0870151613b52565b51825468010000000000000000811015611a3357600181018085558110156138c5576001935f5260205f2001906001600160801b038151167fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffff000000000000000000000000000000006020855494015160801b16921617179055016140ab565b60449250604051917f6375ff1300000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b6040517f210aec0e00000000000000000000000000000000000000000000000000000000815264ffffffffff918216600482015291166024820152604490fd5b91935091936143c6906001600160801b036143bd8588613b52565b5151169061466c565b9364ffffffffff8060206143da8685613b52565b510151169416808511156143f657506001849301909291613efc565b8385606492604051927fd97494c6000000000000000000000000000000000000000000000000000000008452600484015260248301526044820152fd5b64ffffffffff602061444484613b45565b5101516040517ff1fb2cc500000000000000000000000000000000000000000000000000000000815264ffffffffff938416600482015291169091166024820152604490fd5b602490604051907f73627f740000000000000000000000000000000000000000000000000000000082526004820152fd5b60046040517f7ea4ccdf000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd572dbcb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6095d3bc000000000000000000000000000000000000000000000000000000008152fd5b805f5260036020526001600160a01b03908160405f2054169182331492831561457b575b50821561456957505090565b90915061457633926135a0565b161490565b9092505f52600660205260405f20335f5260205260ff60405f205416915f61455d565b805f5260096020526145b5600260405f2001613968565b815f52600960205260405f2060ff600182015460a01c165f146145e557506001600160801b039150602001511690565b5460f81c6145fa57506145f790613b66565b90565b6145f791506001600160801b0360408183511692015116906135c2565b3d15614641573d9061462882613570565b91614636604051938461354e565b82523d5f602084013e565b606090565b6145f7906146538161459e565b905f526009602052600260405f20015460801c906135c2565b9190916001600160801b03808094169116019182116135db57565b919091604051614696816134f9565b5f81525f6020820152926001600160801b039182811691821561473b5767016345785d8a000080821161470457506146cf8491846148b3565b16602086019281845211156146f057826146eb925116906135c2565b168252565b634e487b7160e01b5f52600160045260245ffd5b60449250604051917f4fea5c1a00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b50505050905060405161474d816134f9565b5f81525f602082015290565b9290604051927f23b872dd0000000000000000000000000000000000000000000000000000000060208501526001600160a01b03809216602485015216604483015260648201526064815260a081019181831067ffffffffffffffff841117611a33576147c89260405261481f565b565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b039290921660248301526044808301939093529181526147c89161481f60648361354e565b5f806001600160a01b0361484893169360208151910182865af1614841614617565b9083614961565b805190811515918261488f575b505061485e5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b819250906020918101031261062a576020015180159081150361062a575f80614855565b9091905f198382098382029182808310920391808303921461495057670de0b6b3a7640000908183101561491957947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906149a0575080511561497657805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b815115806149eb575b6149b1575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156149a956fea164736f6c6343000817000a"; + hex"60c0604052346103e457614ebd6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614aaf908161040e823960805181613eb8015260a051818181612f4e0152613f610152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613445565b604435926001600160801b0384169384810361063957610295613eae565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614706565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61472c565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a20016139fc565b6001600160801b036103bb8160208401511692826040818351169201511690613630565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c8861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135bc565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135bc565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e8846145e1565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613445565b61073a83614706565b92610743613eae565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614706565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b03604061082861342f565b9282610832613445565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614706565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613b93565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561340a565b0390f35b90503d8083833e6109e381836135bc565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a846135de565b92610a2860405194856135bc565b848452602085840101116104d657506109ce92610a4b91602080850191016133e9565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613445565b91610a87613eae565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614706565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d62565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613eae565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614706565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61472c565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d600260408920016139fc565b6001600160801b03610c718160208401511692826040818351169201511690613630565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc381868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135bc565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135bc565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e91856145e1565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb61342f565b611003613445565b906064359067ffffffffffffffff821161063957366023830112156106395781600401359284611032856135de565b9361104060405195866135bc565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a4f565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613cce565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a461342f565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135bc565b60405191829160208352602083019061340a565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613cce565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613eae565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138bb565b956114cc60405197886135bc565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138bb565b9261150360405194856135bc565b808452601f19611512826138bb565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bc6565b51511664ffffffffff80602061154d85613bc6565b510151168601166040519161156183613567565b8252602082015261157186613bc6565b5261157b85613bc6565b5060015b8281106116555750505061159584600401613a2e565b906115a260248601613a2e565b906115af6044870161395c565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a42565b948161160260a48c01613a42565b976040519d8e613536565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613909565b610100820152613f08565b604051908152f35b806001600160801b0361166a60019385613bd3565b51511664ffffffffff8060206116835f1986018c613bd3565b510151168160206116948689613bd3565b510151160116604051916116a783613567565b825260208201526116b88289613bd3565b526116c38188613bd3565b500161157f565b6020906040516116d981613567565b5f81525f8382015282828901015201611515565b60206040916116fc36856138d3565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d81613583565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135a0565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c1615158952016139fc565b6101208c019081526118818a613cce565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c613583565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b0198895261195490613988565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce916134da565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134a9565b90611a96613eae565b82915b808310611aa4578380f35b611aaf838284613938565b3592611ab9613eae565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613be7565b908086526009602052611b5d600260408820016139fc565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613630565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b858861488a565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135bc565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a60205220613988565b6040519182916020835260208301906134da565b50346104d65760203660031901126104d65760043590611e79613eae565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613cce565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135bc565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65761217661342f565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f061342f565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613b93565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d65760043590612287613970565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d983613567565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134a9565b9060243567ffffffffffffffff8111610639576123549036906004016134a9565b9261235d613eae565b83810361276357845b818110612371578580f35b61237c818386613938565b35612388828487613938565b35875260036020526001600160a01b03604088205416906123b26123ad848988613938565b61395c565b6123ba613eae565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614706565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61472c565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c0600260408920016139fc565b6001600160801b036124e48160208401511692826040818351169201511690613630565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461253681868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135bc565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135bc565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b50612712846145e1565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614653565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613cce565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613eae565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c8816145e1565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b3661346f565b9060405192612a6b6020856135bc565b858452613a4f565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613eae565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613be7565b90805f526009602052612b86600260405f20016139fc565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613630565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b858861488a565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135bc565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613eae565b604051612e2081613536565b612e2c8260040161345b565b8152612e3a6024830161345b565b6020820152612e4b604483016135fa565b604082015260648201356001600160a01b0381168103612d51576060820152612e7660848301613529565b6080820152612e8760a48301613529565b60a0820152612e9860c483016138a9565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138bb565b90612edc60405192836135bc565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e0840152610104369101613909565b6020604091612f2c36896138d3565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f823661346f565b91613664565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613cce565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613be7565b90613630565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa61342f565b60243561310681613b93565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d5157602061225860043561360e565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135bc565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f80ac58cd00000000000000000000000000000000000000000000000000000000602093149081156133bf575b8115613395575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361338e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613387565b5f5b8381106133fa5750505f910152565b81810151838201526020016133eb565b90602091613423815180928185528580860191016133e9565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b8181106134f75750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134ea565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761355357604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761355357604052565b610180810190811067ffffffffffffffff82111761355357604052565b6060810190811067ffffffffffffffff82111761355357604052565b90601f8019910116810190811067ffffffffffffffff82111761355357604052565b67ffffffffffffffff811161355357601f01601f191660200190565b35906001600160801b0382168203612d5157565b61361781613b93565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161365057565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b0316801561389657815f5260036020526001600160a01b0360405f20541615158061388e575b80613871575b61385e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137a9575b6001600160a01b03935085613772575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361375a57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613791825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136f9565b9192905080613807575b156137c0578282916136e9565b82846137d857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613835575b806137b35750825f526005602052336001600160a01b0360405f205416146137b3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613812565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615613699565b506001613693565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135535760051b60200190565b9190826040910312612d51576040516138eb81613567565b60206139048183956138fc816135fa565b8552016138a9565b910152565b9190826040910312612d515760405161392181613567565b602080829461392f8161345b565b84520135910152565b91908110156139485760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b6040519061397d82613567565b5f6020838281520152565b908154613994816138bb565b926139a260405194856135bc565b81845260208401905f5260205f205f915b8383106139c05750505050565b6001602081926040516139d281613567565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139b3565b90604051613a09816135a0565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a5b838284613664565b803b613a68575b50505050565b602091613aae6001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061340a565b03815f865af15f9181613b36575b50613aea5750613aca6146d7565b80519081613ae55782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b2457505f808080613a62565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613b8b575b81613b52602093836135bc565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613abc565b3d9150613b45565b805f5260036020526001600160a01b0360405f205416908115613bb4575090565b637e27328960e01b5f5260045260245ffd5b8051156139485760200190565b80518210156139485760209160051b010190565b9064ffffffffff421691805f52600a602052613c0560405f20613988565b908364ffffffffff6020613c1885613bc6565b5101511611613cc757805f5260096020528364ffffffffff60405f205460c81c161115613ca857506001600160801b03613c5182613bc6565b515116916001925b8251841015613ca1578464ffffffffff6020613c758787613bd3565b5101511611613ca1576001600160801b0360019181613c948787613bd3565b5151160116930192613c59565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613cf05750600490565b805f52600960205260405f205460f81c613d5c57805f52600960205264ffffffffff60405f205460a01c164210613d5757613d2a81613be7565b905f5260096020526001600160801b0380600260405f200154169116105f14613d5257600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e9c575b80613e7f575b613e6d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e36575b1680613e1e575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613dda565b613e55835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613dd3565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613d87565b506001600160a01b0382161515613d81565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ee057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f2a6001600160801b03604084015116602061010085015101519061474c565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145b95780156145915781518015614569577f0000000000000000000000000000000000000000000000000000000000000000811161453e575064ffffffffff6020613f9884613bc6565b510151168110156144fa57505f905f905f81515f905b808210614472575050505064ffffffffff804216911690818110156144445750506001600160801b03169081810361441657505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061417a8751975f19890190613bd3565b51015160c81b169360a01b169116171785555f5b818110614364575050600187016007556001600160a01b036020830151168015613896576141c4886001600160a01b0392613d62565b166143385786826142126001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b038551169030903390614829565b6001600160801b0360208401511680614308575b506001600160a01b03815116946142fd6142df6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142848b613567565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134da565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614332906001600160a01b036060840151166001600160a01b036101008501515116903390614829565b5f614226565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f209061437f8160e0870151613bd3565b51825492680100000000000000008410156135535760018401808255841015613948576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161418e565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614496906001600160801b0361448d8588613bd3565b5151169061472c565b9364ffffffffff8060206144aa8685613bd3565b510151169416808511156144c657506001849301909291613fae565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061450b84613bc6565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614627575b50811561460e575090565b90506001600160a01b03614622339261360e565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614603565b805f52600960205261466a600260405f20016139fc565b90805f52600960205260ff600160405f20015460a01c165f146146985750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ba57506146b790613be7565b90565b6146b791506001600160801b036040818351169201511690613630565b3d15614701573d906146e8826135de565b916146f660405193846135bc565b82523d5f602084013e565b606090565b6146b79061471381614653565b905f526009602052600260405f20015460801c90613630565b906001600160801b03809116911601906001600160801b03821161365057565b91909160405161475b81613567565b5f81525f6020820152926001600160801b03821690811561480c5767016345785d8a000081116147d5576147976001600160801b039183614968565b16602085019181835211156147c1576001600160801b0391826147bc92511690613630565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161481d81613567565b5f81525f602082015290565b9091926001600160a01b036148889481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148836084836135bc565b6148da565b565b614888926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148836064836135bc565b5f806001600160a01b0361490393169360208151910182865af16148fc6146d7565b9083614a16565b8051908115159182614944575b50506149195750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614910565b9091905f1983820983820291828083109203918083039214614a0557670de0b6b3a76400008210156149d5577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a535750805115614a2b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a99575b614a64575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a5c56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"6080806040523461001757615ec990816200001c8239f35b5f80fdfe600436101561000c575f80fd5b5f3560e01c63e9dc63751461001f575f80fd5b3461440f57604036600319011261440f576001600160a01b03600435166004350361440f576102206040525f6080819052606060a081905260c082905260e08290526101008190526101208190526101608190526101808190526101a08190526101c0526101e0819052610200526004356001600160a01b038116610140526100a790614b17565b610160526100bf6004356001600160a01b0316614d2d565b61018052610140516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f916148e8575b506001600160a01b0361012f911680608052614e35565b60a052610140516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561441b576fffffffffffffffffffffffffffffffff915f916148c9575b501660c052610140516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa801561441b575f9061488c575b6101fb9150614f80565b6101a052610140516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f9161485d575b5060c0516fffffffffffffffffffffffffffffffff168015614849576fffffffffffffffffffffffffffffffff6127108193021604166101606080015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102cb81614977565b51902061040b60296102ed63ffffffff61016861ffff8660101c1606166156ca565b61031b63ffffffff601e604660ff6103118460146050848d60081c160601166156ca565b98160601166156ca565b6040519485927f68736c2800000000000000000000000000000000000000000000000000000000602085015261035b815180926020602488019101614931565b83017f2c000000000000000000000000000000000000000000000000000000000000006024820152610397825180936020602585019101614931565b7f252c000000000000000000000000000000000000000000000000000000000000602583830101526103d58351809460206027868601019101614931565b01017f25290000000000000000000000000000000000000000000000000000000000006027820152036009810184520182614a03565b6104436fffffffffffffffffffffffffffffffff6040608001511660ff61043c6001600160a01b036080511661507a565b16906151d7565b6104576001600160a01b0360805116614d2d565b90602060800151602460206001600160a01b0360c06080015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa801561441b576024915f9161482a575b5060206001600160a01b0360c06080015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa801561441b5761051b925f916147fb575b5064ffffffffff8091169116615505565b610180516101e0519092916105a56021610542606461053b8187066159c7565b95046156ca565b604051948161055b879351809260208087019101614931565b82016105708251809360208085019101614931565b017f25000000000000000000000000000000000000000000000000000000000000006020820152036001810185520183614a03565b6101606080015192610120608001519660e06080015196604051998a61014081011067ffffffffffffffff6101408d01111761442e576101408b016040528a5260208a015260408901526060880152608087015260a086015260c085015260e0840152610100830152610120820152604051806101c081011067ffffffffffffffff6101c08301111761442e576101c08101604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a08201516106aa60c0840151845190615ad3565b9061099061015c604051926106be846149e7565b600884527f50726f677265737300000000000000000000000000000000000000000000000060208501526107006040516106f781614993565b5f81528661598a565b156147f3576090945b610712866156ca565b916040519586938493661e339034b21e9160c91b602086015261095e8351958692610744846027840160208901614931565b6d11103334b6361e9111b33333111f60911b602785840101526c1e3932b1ba103bb4b23a341e9160991b6035858401015261078b8551809660206042888701019101614931565b7f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033828501860160428101919091527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e882015286519661089191889160f990910190602001614931565b661e17ba32bc3a1f60c91b8285018601870160f98101919091527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b61014082015287519761092c91899161015190910190602001614931565b661e17ba32bc3a1f60c91b6101518888888887010101010152602061015888888885519c8d9701010101019101614931565b631e17b39f60e11b90860190910190910190910190910161015881019190915281900361013c81019091520182614a03565b6101008301526101208201526028610120830151604051906109b182614993565b5f8252610c5661015c604051926109c7846149e7565b600684527f537461747573000000000000000000000000000000000000000000000000000060208501526109fa84615dcf565b610a0382615e49565b808211156147eb5750945b610a198787016156ca565b91604051958693661e339034b21e9160c91b60208601528151610a43816027880160208601614931565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610a86825180936020604285019101614931565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610b8282518093602060f985019101614931565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610c1182518093602061015185019101614931565b01661e17ba32bc3a1f60c91b610151820152610c3882518093602061015885019101614931565b01631e17b39f60e11b6101588201520361013c810184520182614a03565b610160840152016101808201526028602083015160405190610c7782614993565b5f8252610cc061015c60405192610c8d846149e7565b600684527f416d6f756e74000000000000000000000000000000000000000000000000000060208501526109fa84615dcf565b8352016020820152610ffa60808301516030604051610cde81614993565b5f8152610f8461015c60405194610cf4866149e7565b600886527f4475726174696f6e0000000000000000000000000000000000000000000000006020870152610d2786615dcf565b610d3082615e49565b808211156147e35750935b610d47602886016156ca565b91604051978893661e339034b21e9160c91b60208601528151610d71816027880160208601614931565b85016d11103334b6361e9111b33333111f60911b60278201526c1e3932b1ba103bb4b23a341e9160991b6035820152610db4825180936020604285019101614931565b017f22206865696768743d22313030222066696c6c2d6f7061636974793d222e303360428201527f222072783d223135222072793d22313522207374726f6b653d2223666666222060628201527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d77696474686082820152651e911a11179f60d11b60a28201527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60a88201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060c8820152703337b73a16b9b4bd329e911919383c111f60791b60e8820152610eb082518093602060f985019101614931565b01661e17ba32bc3a1f60c91b60f98201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d6101008201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f73706163652220610120820152703337b73a16b9b4bd329e91191b383c111f60791b610140820152610f3f82518093602061015185019101614931565b01661e17ba32bc3a1f60c91b610151820152610f6682518093602061015885019101614931565b01631e17b39f60e11b6101588201520361013c810186520184614a03565b8260a08601526028810160c0860152602085015190610120860151809161018088015192839185010101605881016080890152605719906103e8030160011c8061014089015201601081016101a088015201602081016040870152010160e084015261010083015161016084015184519161516d565b6060820152604051908161010081011067ffffffffffffffff6101008401111761442e57610100820160405260c782527f3c726563742077696474683d223130302522206865696768743d22313030252260208301527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260408301527f37302220793d223730222077696474683d2238363022206865696768743d223860608301527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060808301527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a08301527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c08301527f683d2234222f3e0000000000000000000000000000000000000000000000000060e083015282519161012084015191606081015194604051611150816149af565b603381527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d2260208201527f75726c282352616469616c476c6f7729222f3e000000000000000000000000006040820152604051968761014081011067ffffffffffffffff6101408a01111761442e57610140880160405261011c88527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d223060208901527f2220793d2230222077696474683d223130302522206865696768743d2231303060408901527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c3131252960608901527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808901527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08901527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08901527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08901527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c22206101008901527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e0000000061012089015260405197886103a081011067ffffffffffffffff6103a08b01111761442e576103a0890160405261037b89527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c60208a01527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408a01527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c60608a01527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808a01527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08a01527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08a01527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08a01527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e6101008a01527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208a01527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c366101408a01527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608a01527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808a01527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08a01527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08a01527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08a01527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008a01527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208a01527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408a01527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608a01527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808a01527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08a01527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08a01527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08a01527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008a01527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208a01527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408a01527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608a01527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808a0152604051978860a081011067ffffffffffffffff60a08b01111761442e57611ca5611d069160a08b0160405260758b527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f60208c01527f6e652220643d224d31323520343568373530733830203020383020383076373560408c01527f307330203830202d3830203830682d373530732d38302030202d3830202d383060608c01527f762d3735307330202d3830203830202d3830222f3e000000000000000000000060808c015261185c615a9a565b906040517f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e6020820152611d0160d87f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d22000093846040850152805161198e60b88660208501936118ce81605e840187614931565b8101997f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000605e8c01527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d229a8b6073820152611933825180936020609385019101614931565b017f222073746f702d6f7061636974793d2230222f3e00000000000000000000000060938201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060a7820152036098810188520186614a03565b611996615a9a565b90604051967f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d60208901527f223025222079313d223025223e000000000000000000000000000000000000006040890152604d88015282516119fc81606b8a0184614931565b8701917f222f3e00000000000000000000000000000000000000000000000000000000009283606b82015289606e820152611a41825180936020608e85019101614931565b019082608e830152611a8560a2897f3c2f6c696e6561724772616469656e743e0000000000000000000000000000009485609182015203608281018b520189614a03565b611bcb610108611a93615a9a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d222060208401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d22006054840152611b1f815180926020607387019101614931565b8201908760738301526076820152875190611b3e826096830188614931565b018660968201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60998201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160b98201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e000060d98201528560f78201520360e881018c52018a614a03565b611bd3615a9a565b906040519a8b957f3c6c696e6561724772616469656e742069643d22486f7572676c61737353747260208801527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408801527f302922206772616469656e74556e6974733d227573657253706163654f6e557360608801527f65223e000000000000000000000000000000000000000000000000000000000060808801527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d2200608388015251809260a2880190614931565b84018360a28201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a5820152611ce782518093602060c485019101614931565b019160c483015260c78201520360b8810187520185614a03565b61516d565b92611d18611d12614f0e565b8961598a565b9788156147c8575b50604051611d2d816149cb565b609081527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c60208201527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408201527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e303222207360608201527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808201527f726f6b652d77696474683d2234222f3e0000000000000000000000000000000060a082015260405193846102c081011067ffffffffffffffff6102c08701111761442e576102c0850160405261029885527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d60208601527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e3160408601527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d3160608601527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d31353260808601527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e343160a08601527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c60c08601527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e08601527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101008601527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c31396101208601527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c6101408601527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e6101608601527f3630322c32312e303739733131312e3833312d372e3438372c3135322e3538376101808601527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a08601527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c08601527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e08601527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e326102008601527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e37396102208601527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e30316102408601527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d6102608601527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a6102808601527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a0860152895f146145a35760405161215a81614993565b5f8152995b1561444257604051806101e081011067ffffffffffffffff6101e08301111761442e576101e081016040526101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d3260208201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d353360608201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a60a08201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7061746860c08201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e6101008201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e6101408201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152995b60405196876107e081011067ffffffffffffffff6107e08a01111761442e57613b6c9c612e276036602d9960819f97631e17b39f60e11b8d7f3c2f646566733e000000000000000000000000000000000000000000000000009a612ef89f6107e0016040526107a782527f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f757260208301527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408301527f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f60608301527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c3160808301527f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373660a08301527f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e313960c08301527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e08301527f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e33356101008301527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e3935336101208301527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e366101408301527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608301527f2c39362e3535342d37312e3932312c3231352e3635322d37312e3932317332316101808301527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08301527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c08301527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08301527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c6102008301527f696e652078313d223133342e3336222079313d223136312e323033222078323d6102208301527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408301527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608301527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808301527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08301527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d226102c08301527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08301527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008301527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208301527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408301527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608301527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c31306103808301527f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c31326103a08301527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08301527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08301527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008301527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208301527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408301527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608301527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808301527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08301527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08301527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08301527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008301527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208301527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408301527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608301527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808301527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08301527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08301527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08301527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008301527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208301527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408301527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608301527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808301527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08301527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08301527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08301527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008301527f2e383232203438312e393031203438312e373938203438312e383737203438316107208301527f2e373735203438312e383534203335302e303135203335302e303236203231386107408301527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608301527f223231382e313835203438312e393031203231382e323331203438312e3835346107808301527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08301527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0830152604051998a957f3c672069643d22486f7572676c617373223e00000000000000000000000000006020880152603295612dc38151809260208a8c019101614931565b8701612dd88251809360208a85019101614931565b01612dec8251809360208985019101614931565b01612e008251809360208885019101614931565b01612e148251809360208785019101614931565b0191820152036016810186520184614a03565b6040519e8f9788977f3c646566733e000000000000000000000000000000000000000000000000000060208a0152612e6c6026998260208c9451948593019101614931565b8901612e818251809360208c85019101614931565b01612e958251809360208b85019101614931565b01612ea98251809360208a85019101614931565b01612ebd8251809360208985019101614931565b01612ed18251809360208885019101614931565b01612ee58251809360208785019101614931565b019182015203600d810189520187614a03565b61378b604c60e0830151610100840151936134e761311a6060604084015193015196612f248186615d13565b9461311561012b604051612f37816149e7565b600581527f2d3130302500000000000000000000000000000000000000000000000000000060208201526040519889917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152612fa1815180926020603787019101614931565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666683820160378101919091527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528251926130e591849161012090910190602001614931565b6a1e17ba32bc3a2830ba341f60a91b90830190910161012081019190915281900361010b81019091520187614a03565b615d13565b956132f961012b60405161312d816149e7565b600281527f30250000000000000000000000000000000000000000000000000000000000006020820152604051998a917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613197815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526132d482518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b81018a520188614a03565b6133038184615d7b565b926134e261012b604051613316816149e7565b600481527f2d3530250000000000000000000000000000000000000000000000000000000060208201526040519687917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613380815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526134bd82518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810187520185614a03565b615d7b565b906136c661012b6040516134fa816149e7565b600381527f353025000000000000000000000000000000000000000000000000000000000060208201526040519485917f3c74657874506174682073746172744f66667365743d220000000000000000006020840152613564815180926020603787019101614931565b82017f2220687265663d2223466c6f6174696e6754657874222066696c6c3d2223666660378201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201526136a182518093602061012085019101614931565b016a1e17ba32bc3a2830ba341f60a91b6101208201520361010b810185520183614a03565b6040519586937f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537060208601527f656564223e000000000000000000000000000000000000000000000000000000604086015261372c815180926020604589019101614931565b8401613742825180936020604585019101614931565b01613757825180936020604585019101614931565b0161376c825180936020604585019101614931565b01661e17ba32bc3a1f60c91b604582015203602c810184520182614a03565b613a6b61019a6101408401516101a0850151906137cc6137c66137c06137ba60e060408b01519a0151946156ca565b946156ca565b976156ca565b916156ca565b956040519687937f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2260208601527f2e39222f3e00000000000000000000000000000000000000000000000000000060408601527f3c75736520687265663d2223476c6f772220783d22313030302220793d22313060458601527f3030222066696c6c2d6f7061636974793d222e39222f3e00000000000000000060658601527f3c75736520687265663d22234c6f676f2220783d223137302220793d22313730607c8601527f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872609c8601527f65663d2223486f7572676c6173732220783d223135302220793d22393022207460bc8601527f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d60dc8601527f6f726967696e3d2235303020353030222f3e000000000000000000000000000060fc8601527f3c75736520687265663d222350726f67726573732220783d220000000000000061010e86015261012790613967815180926020858a019101614931565b8501937f2220793d22373930222f3e00000000000000000000000000000000000000000080948180948801527f3c75736520687265663d22235374617475732220783d22000000000000000000610132880152610149966139d18251809360208b85019101614931565b01958601527f3c75736520687265663d2223416d6f756e742220783d2200000000000000000061015486015261016b94613a148251809360208985019101614931565b01938401527f3c75736520687265663d22234475726174696f6e2220783d220000000000000061017684015261018f92613a578251809360208785019101614931565b01918201520361017a810185520183614a03565b6040519586937f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208601527f30302f737667222077696474683d223130303022206865696768743d2231303060408601527f30222076696577426f783d2230203020313030302031303030223e00000000006060860152613af7815180926020607b89019101614931565b8401613b0d825180936020607b85019101614931565b01613b22825180936020607b85019101614931565b01613b37825180936020607b85019101614931565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000607b820152036061810184520182614a03565b610140608001525f806001600160a01b0360c0608001511660405160208101907fb2564569000000000000000000000000000000000000000000000000000000008252602435602482015260248152613bc4816149af565b51915afa613bd0614a86565b61012081905290158015610200526144265760208180518101031261440f5760200151801515810361440f575b151560e05260a051610140516040517fb971302a0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa90811561441b575f916143d1575b506141e26142d3609461434594613d9b6089613c786142de97614d2d565b92610120608001516040519485927f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a226020850152613cc0815180926020604088019101614931565b8301907f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c756560408301527f223a22000000000000000000000000000000000000000000000000000000000091826060820152613d25825180936020606385019101614931565b01907f227d2c7b2274726169745f74797065223a22537461747573222c2276616c756560638301526083820152613d66825180936020608685019101614931565b017f227d5d00000000000000000000000000000000000000000000000000000000006086820152036069810184520182614a03565b6101605160a0516101805160805190926140cc9160e39190613dc5906001600160a01b0316614d2d565b94613dd16024356156ca565b60e0519096901561434957604051613de8816149cb565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e672074686560208201527f204e4654206d616b657320746865206e6577206f776e6572207468652072656360408201527f697069656e74206f66207468652073747265616d2e205468652066756e64732060608201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000060a0820152915b60405197889461406860208701997f54686973204e465420726570726573656e74732061207061796d656e742073748b527f7265616d20696e2061205361626c696572205632200000000000000000000000604089015282516020840190613f188160558c0184614931565b8901947f20636f6e74726163742e20546865206f776e6572206f662074686973204e465460558701527f2063616e207769746864726177207468652073747265616d656420617373657460758701527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609587015282516020840196613fa28260b183018a614931565b017f2e5c6e5c6e2d2053747265616d2049443a20000000000000000000000000000060b1820152613fdd82518093602060c385019101614931565b016140167f5c6e2d2000000000000000000000000000000000000000000000000000000000958660c384015251809360c7840190614931565b01947f20416464726573733a2000000000000000000000000000000000000000000000958660c782015261405482518093602060d185019101614931565b019260d184015251809360d5840190614931565b019060d582015261408382518093602060df85019101614931565b017f5c6e5c6e0000000000000000000000000000000000000000000000000000000060df8201526140bd8251809360208785019101614931565b010360c3810185520183614a03565b610160519061423d6140df6024356156ca565b9161415e602d604051809560208201976a029b0b13634b2b9102b19160ad1b8952614114815180926020602b87019101614931565b82017f2023000000000000000000000000000000000000000000000000000000000000602b82015261414f8251809360208785019101614931565b0103600d810186520184614a03565b6101c05161416b90615819565b94604051998a977f7b2261747472696275746573223a00000000000000000000000000000000000060208a01526141ac815180926020602e8d019101614931565b8801917f2c226465736372697074696f6e223a2200000000000000000000000000000000602e840152518093603e840190614931565b01917f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c6965603e8401527f722e636f6d222c226e616d65223a220000000000000000000000000000000000605e840152518093606d840190614931565b017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b6261606d8201527f736536342c000000000000000000000000000000000000000000000000000000608d82015261429e825180936020609285019101614931565b017f227d0000000000000000000000000000000000000000000000000000000000006092820152036074810184520182614a03565b610100819052615819565b614331603d60405180937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000060208301526143218151809260208686019101614931565b810103601d810184520182614a03565b604051918291602083526020830190614952565b0390f35b60405161435581614977565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e73666560208201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e60408201527f7366657272656420746f20616e6f74686572206163636f756e742e0000000000606082015291613eac565b90506020813d602011614413575b816143ec60209383614a03565b8101031261440f5751906001600160a01b038216820361440f57906141e2613c5a565b5f80fd5b3d91506143df565b6040513d5f823e3d90fd5b506001613bfd565b634e487b7160e01b5f52604160045260245ffd5b6040518061012081011067ffffffffffffffff6101208301111761442e57610120810160405260f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e3434396360208201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d60608201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e6460a08201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d2260c08201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610100820152996123ac565b604051806101c081011067ffffffffffffffff6101c08301111761442e576101c0810160405261019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e3032362034313560208201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c7060608201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e30373660a08201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e36323460c08201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e6101008201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c336101408201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a08201529961215f565b6147dc9198506147d6614f47565b9061598a565b965f611d20565b905093610d3b565b905094610a0e565b60d094610709565b61481d915060203d602011614823575b6148158183614a03565b810190614a4d565b5f61050a565b503d61480b565b614843915060203d602011614823576148158183614a03565b5f6104b4565b634e487b7160e01b5f52601260045260245ffd5b61487f915060203d602011614885575b6148778183614a03565b810190614a25565b5f610254565b503d61486d565b506020813d6020116148c1575b816148a660209383614a03565b8101031261440f5751600581101561440f576101fb906101f1565b3d9150614899565b6148e2915060203d602011614885576148778183614a03565b5f610198565b90506020813d602011614929575b8161490360209383614a03565b8101031261440f57516001600160a01b038116810361440f576001600160a01b03610118565b3d91506148f6565b5f5b8381106149425750505f910152565b8181015183820152602001614933565b9060209161496b81518092818552858086019101614931565b601f01601f1916010190565b6080810190811067ffffffffffffffff82111761442e57604052565b6020810190811067ffffffffffffffff82111761442e57604052565b6060810190811067ffffffffffffffff82111761442e57604052565b60c0810190811067ffffffffffffffff82111761442e57604052565b6040810190811067ffffffffffffffff82111761442e57604052565b90601f8019910116810190811067ffffffffffffffff82111761442e57604052565b9081602091031261440f57516fffffffffffffffffffffffffffffffff8116810361440f5790565b9081602091031261440f575164ffffffffff8116810361440f5790565b67ffffffffffffffff811161442e57601f01601f191660200190565b3d15614ab0573d90614a9782614a6a565b91614aa56040519384614a03565b82523d5f602084013e565b606090565b60208183031261440f5780519067ffffffffffffffff821161440f570181601f8201121561440f578051614ae881614a6a565b92614af66040519485614a03565b8184526020828401011161440f57614b149160208085019101614931565b90565b6001600160a01b031660408051916395d89b4160e01b83525f83600481845afa928315614d23575f93614cff575b50815192614b52846149e7565b60118452614b876020947f5341422d56322d4c4f434b55502d4c494e000000000000000000000000000000868201528261598a565b15614bc55750507f4c6f636b7570204c696e65617200000000000000000000000000000000000000905191614bbb836149e7565b600d835282015290565b614c028351614bd3816149e7565b601181527f5341422d56322d4c4f434b55502d44594e000000000000000000000000000000868201528261598a565b15614c405750507f4c6f636b75702044796e616d6963000000000000000000000000000000000000905191614c36836149e7565b600e835282015290565b614c7d8351614c4e816149e7565b601181527f5341422d56322d4c4f434b55502d545241000000000000000000000000000000868201528261598a565b15614cbb5750507f4c6f636b7570205472616e636865640000000000000000000000000000000000905191614cb1836149e7565b600f835282015290565b614cfb9083519384937f814a8a2e000000000000000000000000000000000000000000000000000000008552600485015260248401526044830190614952565b0390fd5b614d1c9193503d805f833e614d148183614a03565b810190614ab5565b915f614b45565b82513d5f823e3d90fd5b6001600160a01b03168060405191614d44836149af565b602a8352602083016040368237835115614e215760309053825160019060011015614e2157607860218501536029905b808211614dbd575050614d85575090565b604490604051907fe22e27eb000000000000000000000000000000000000000000000000000000008252600482015260146024820152fd5b9091600f81166010811015614e21577f3031323334353637383961626364656600000000000000000000000000000000901a614df984876159b6565b5360041c918015614e0d575f190190614d74565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614e57816149e7565b51915afa614e63614a86565b90158015614f02575b614ec85780602080614e8393518301019101614ab5565b601e8151115f14614b145750604051614e9b816149e7565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614ed5816149e7565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614e6c565b60405190614f1b826149e7565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614f54826149e7565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b60058110156150665760048103614f9a5750614b14614f47565b60038103614fdc5750604051614faf816149e7565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b6001810361501e5750604051614ff1816149e7565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b60020361502d57614b14614f0e565b604051615039816149e7565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce567000000000000000000000000000000000000000000000000000000008252600481526150b5816149e7565b51915afa6150c1614a86565b90806150f0575b156150eb5760208180518101031261440f576020015160ff8116810361440f5790565b505f90565b5060208151146150c8565b60405190615108826149e7565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615141826149e7565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b906151d592949360405195869260209461518f81518092888089019101614931565b84016151a382518093888085019101614931565b016151b682518093878085019101614931565b016151c982518093868085019101614931565b01038085520183614a03565b565b9081156154ca57806154ba57505b600190808281101561524f575050506151fc615134565b614b14602260405183615219829551809260208086019101614931565b81017f20310000000000000000000000000000000000000000000000000000000000006020820152036002810184520182614a03565b66038d7ea4c68000111561545d5760409081519060a0820182811067ffffffffffffffff82111761442e5780845261528681614993565b5f81528252825190615297826149e7565b8482526020917f4b00000000000000000000000000000000000000000000000000000000000000838201528284015283516152d1816149e7565b8581527f4d0000000000000000000000000000000000000000000000000000000000000083820152848401528351615308816149e7565b8581527f42000000000000000000000000000000000000000000000000000000000000008382015260608401528351615340816149e7565b8581527f54000000000000000000000000000000000000000000000000000000000000008382015260808401525f91855f965b615431575b50845194615385866149e7565b600790600787527f2623383830353b000000000000000000000000000000000000000000000000008388015251955f5b82811061541e57505050506153ff615405917f20000000000000000000000000000000000000000000000000000000000000006027870152600886526153fa866149e7565b6156ca565b916159c7565b916005851015614e2157614b149460051b01519261516d565b81810184015188820185015283016153b5565b9591926103e89081851061545457508680916064600a8704069504930196615373565b93929650615378565b50506154676150fb565b614b14602860405183615484829551809260208086019101614931565b81017f203939392e3939540000000000000000000000000000000000000000000000006020820152036008810184520182614a03565b600a0a90811561484957046151e5565b50506040516154d8816149e7565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061556d575061551a615134565b614b14602660405183615537829551809260208086019101614931565b81017f20312044617900000000000000000000000000000000000000000000000000006020820152036006810184520182614a03565b61270f811161563c57600181036155f957614b1460206155c1604051615592816149e7565b600481527f204461790000000000000000000000000000000000000000000000000000000083820152936156ca565b60405193816155d98693518092868087019101614931565b82016155ed82518093868085019101614931565b01038084520182614a03565b614b1460206155c160405161560d816149e7565b600581527f204461797300000000000000000000000000000000000000000000000000000083820152936156ca565b506156456150fb565b614b14602a60405183615662829551809260208086019101614931565b81017f2039393939204461797300000000000000000000000000000000000000000000602082015203600a810184520182614a03565b906156a282614a6a565b6156af6040519182614a03565b82815280926156c0601f1991614a6a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008082101561580b575b506d04ee2d6d415b85acef8100000000808310156157fc575b50662386f26fc10000808310156157ed575b506305f5e100808310156157de575b50612710808310156157cf575b5060648210156157bf575b600a809210156157b5575b60019081602161576160018701615698565b95860101905b615773575b5050505090565b5f19019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156157b057919082615767565b61576c565b916001019161574f565b9190606460029104910191615744565b6004919392049101915f615739565b6008919392049101915f61572c565b6010919392049101915f61571d565b6020919392049101915f61570b565b60409350810491505f6156f2565b90815115615976576040519161582e836149af565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f604084015280519260029160028501809511614e0d5760038095047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614e0d576158cc9060029694961b615698565b9260208401928291835184019760208901928351945f85525b8a8110615929575050505060039394959650525106806001146159175760021461590d575090565b603d905f19015390565b50603d90815f19820153600119015390565b836004919b989b019a8b51600190603f9082828260121c16870101518453828282600c1c16870101518385015382828260061c1687010151878501531684010151858201530196996158e5565b905060405161598481614993565b5f815290565b90815181519081811493846159a0575050505090565b602092939450820120920120145f80808061576c565b908151811015614e21570160200190565b806159d9575060405161598481614993565b600a811015615a3e576159eb906156ca565b614b14602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a2e8151809260208686019101614931565b8101036002810184520182614a03565b615a47906156ca565b614b14602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a8a8151809260208686019101614931565b8101036001810184520182614a03565b60405190615aa7826149e7565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d0557615ae1615a9a565b90612710908103908111614e0d57614b1491615aff610136926156ca565b6040519485927f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208501527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8501527f7374726f6b653d22000000000000000000000000000000000000000000000000604f850152615b8b815180926020605788019101614931565b83017f22207374726f6b652d77696474683d223130222f3e000000000000000000000060578201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c1382518093602060a785019101614931565b017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b60a78201527f652d646173686f66667365743d2200000000000000000000000000000000000060c7820152615c7482518093602060d585019101614931565b017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d60d58201527f77696474683d223522207472616e73666f726d3d22726f74617465282d39302960f58201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000610115820152631e17b39f60e11b61013282015203610116810184520182614a03565b505060405161598481614993565b60306151d5919392936040519481615d35879351809260208087019101614931565b820164010714051160dd1b60208201526a029b0b13634b2b9102b19160ad1b6025820152615d6c8251809360208785019101614931565b01036010810185520183614a03565b60256151d5919392936040519481615d9d879351809260208087019101614931565b820164010714051160dd1b6020820152615dc08251809360208785019101614931565b01036005810185520183614a03565b5f9080518015615e4257905f915f915b818310615df157505050600d02900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e2487856159b6565b511614615e3a575b600d01936001019190615ddf565b849350615e2c565b5050505f90565b5f9080518015615e4257905f915f915b818310615e6b5750505060041b900390565b909193603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e9e87856159b6565b511614615eb4575b601001936001019190615e59565b849350615ea656fea164736f6c6343000817000a"; + hex"60808060405234601557615cfe908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614c8e565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166153f3565b9701166153f3565b9801166153f3565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614d8e565b1690614ef4565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615222565b610340516103a05190939091906105ac600161054a60646105438188066156fb565b96046153f3565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906157fc565b60b76106ed5f615aef565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156bd565b1561456e57601b60909a5b6107298c6153f3565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615aef565b98601b6028610a1a8c615bfa565b610a2384615c79565b8082111561456757505b019a6107298c6153f3565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615aef565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615aef565b9660b7610ac189615bfa565b610aca8b615c79565b8082111561455f5750995b601b8c8c019a6107298c6153f3565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614e87565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c601460226114096157c1565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c6157c1565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df607260236116646157c1565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e76157c1565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614e87565b60e05261195561194f614c18565b856156bd565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615a40565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615a40565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615aaa565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615aaa565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d906153f3565b916134a7906153f3565b906134b1906153f3565b936134bb906153f3565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b076024356153f3565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e6024356153f3565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615552565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615552565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614c53565b906156bd565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156bd565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156bd565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156bd565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ea565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c0c575b614bd05780602080614b89935183010191016147c5565b601e8151115f146148245750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614bdf604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c27604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614c62604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614d7a5760048103614ca85750614824614c53565b60038103614cec5750604051614cbf604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d305750604051614d03604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d3f57614824614c18565b604051614d4d604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614dcb602482614713565b51915afa614dd7614796565b9080614e06575b15614e01576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614dde565b60405190614e20604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614e5b604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eb29493614ee36020614ef295614ed5828096816040519c8d8b83829d519485930191016146cd565b8901614ec6825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b9081156151e557806151d557505b806001811015614f6b575050614f16614e4c565b6148246002602060405184614f3482965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c680001115615177576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614fa78482614713565b5f815281526040918251614fbb8482614713565b600181527f4b0000000000000000000000000000000000000000000000000000000000000085820152848301528251614ff48482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161502d8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150678482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561515d578451946150b18187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061514a5750507f2000000000000000000000000000000000000000000000000000000000000000602786015250600884526151319061512b90615126602887614713565b6153f3565b916156fb565b916005851015614b25576148249460051b015192614e87565b81810183015187820184015282016150de565b9490915060016103e86064600a850406930491019461509a565b50615180614e11565b614824600860206040518461519e82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f02565b50506040516151f5604082614713565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061528c5750615237614e4c565b614824600660206040518461525582965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f8111615363576001810361531f576148246152e16040516152b1604082614713565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926153f3565b602060405193826152fb86945180928580880191016146cd565b830161530f825180938580850191016146cd565b010103601f198101835282614713565b6148246152e1604051615333604082614713565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926153f3565b5061536c614e11565b614824600a60206040518461538a82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153cb8261477a565b6153d86040519182614713565b82815280926153e9601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561552a575b806d04ee2d6d415b85acef8100000000600a92101561550f575b662386f26fc100008110156154fb575b6305f5e1008110156154ea575b6127108110156154db575b60648110156154cd575b10156154c2575b600a602161547d600185016153c1565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154bd57600a9091615482565b505090565b60019091019061546d565b606460029104930192615466565b6127106004910493019261545c565b6305f5e10060089104930192615451565b662386f26fc1000060109104930192615444565b6d04ee2d6d415b85acef810000000060209104930192615434565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461541a565b908151156156a75760405191615569606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576155ff9060021b6153c1565b90602082019080815182019560208701908151925f83525b88811061565957505060039394959650525106806001146156475760021461563d575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c1687010151600285015316840101516003820153019497615617565b90506040516156b7602082614713565b5f815290565b90815181519081811493846156d4575b5050505090565b602092939450820120920120145f8080806156cd565b908151811015614b25570160200190565b8061570f57506040516156b7602082614713565b600a81101561577557615721906153f3565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261576481518092602086860191016146cd565b81010301601f198101835282614713565b61577e906153f3565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261576481518092602086860191016146cd565b604051906157d0604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615a305761580a6157c1565b9061271003906127108211614b1157602e606191605061582c614824956153f3565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f8701526158b9815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c82015261594082518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d2200000000000000000000000000000000000060708201526159a1825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156b7602082614713565b6010614ef29193929360206040519582615a6388945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615a9982518093856030850191016146cd565b01010301601f198101845283614713565b6005614ef29193929360206040519582615acd88945180928580880191016146cd565b830164010714051160dd1b83820152615a9982518093856025850191016146cd565b6004811015614d7a5780615b395750604051615b0c604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615b7d5750604051615b50604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615bbf57604051615b92604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615bcd604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f9080518015615c725790600d915f925f925b828410615c205750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615c5488856156ea565b511614615c6a575b820194600101929190615c0d565b859450615c5c565b5050505f90565b5f9080518015615c7257906010915f925f925b828410615c9f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615cd388856156ea565b511614615ce9575b820194600101929190615c8c565b859450615cdb56fea164736f6c634300081a000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS From e8b9041d79153b00406843ff4a1461868f5507d3 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 17 Jun 2024 08:43:06 +0200 Subject: [PATCH 115/132] test(chore): correct typo --- .../lockup-linear/streamed-amount-of/streamedAmountOf.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index b1a94746d..beda0bc05 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -19,7 +19,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is StreamedAmountOf_Integration_Concrete_Test.setUp(); } - modifier givenStatusPendind() { + modifier givenStatusPending() { _; } @@ -27,7 +27,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is external givenNotNull givenStreamHasNotBeenCanceled - givenStatusPendind + givenStatusPending { vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); From 6a3c917ce052bbcda78d6b1dbf1bff305f169e79 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:13:41 +0200 Subject: [PATCH 116/132] refactor: disallow non alphanumeric symbols (#945) * refactor: disallow non alphanumeric symbols * feat: allow empty spaces in "isAlphanumeric" refactor: alphabetical ordering refactor: return different string test: thorough concrete tests for "isAlphanumeric" * refactor: simplify logical conditions test: fuzz tests for "isAlphanumeric" test: shared test contract for NFT descriptor --------- Co-authored-by: Paul Razvan Berg --- foundry.toml | 6 +- precompiles/Precompiles.sol | 2 +- src/SablierV2NFTDescriptor.sol | 29 ++++- .../nft-descriptor/generateAccentColor.t.sol | 4 +- .../is-alphanumeric/isAlphanumeric.t.sol | 100 ++++++++++++++++++ .../is-alphanumeric/isAlphanumeric.tree | 8 ++ .../nft-descriptor/map-symbol/mapSymbol.t.sol | 4 +- .../safeAssetDecimals.t.sol | 4 +- .../safe-asset-symbol/safeAssetSymbol.t.sol | 24 ++++- .../safe-asset-symbol/safeAssetSymbol.tree | 5 +- .../fuzz/nft-descriptor/isAlphanumeric.t.sol | 46 ++++++++ .../nft-descriptor/NFTDescriptor.t.sol | 2 +- test/mocks/NFTDescriptorMock.sol | 4 + 13 files changed, 221 insertions(+), 17 deletions(-) create mode 100644 test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol create mode 100644 test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree create mode 100644 test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol rename test/integration/{concrete => shared}/nft-descriptor/NFTDescriptor.t.sol (91%) diff --git a/foundry.toml b/foundry.toml index 547b35381..89749dd4f 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,9 +3,9 @@ bytecode_hash = "none" evm_version = "shanghai" fs_permissions = [ - { access = "read", path = "./out-optimized"}, - { access = "read", path = "package.json"}, - { access = "read-write", path = "./benchmark/results"} + { access = "read", path = "./out-optimized" }, + { access = "read", path = "package.json" }, + { access = "read-write", path = "./benchmark/results" }, ] gas_reports = [ "SablierV2LockupDynamic", diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 9f56f79c4..5c230310a 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -32,7 +32,7 @@ contract Precompiles { bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c0604052346103e457614ebd6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614aaf908161040e823960805181613eb8015260a051818181612f4e0152613f610152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613445565b604435926001600160801b0384169384810361063957610295613eae565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614706565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61472c565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a20016139fc565b6001600160801b036103bb8160208401511692826040818351169201511690613630565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c8861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135bc565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135bc565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e8846145e1565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613445565b61073a83614706565b92610743613eae565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614706565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b03604061082861342f565b9282610832613445565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614706565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613b93565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561340a565b0390f35b90503d8083833e6109e381836135bc565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a846135de565b92610a2860405194856135bc565b848452602085840101116104d657506109ce92610a4b91602080850191016133e9565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613445565b91610a87613eae565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614706565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d62565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613eae565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614706565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61472c565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d600260408920016139fc565b6001600160801b03610c718160208401511692826040818351169201511690613630565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc381868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135bc565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135bc565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e91856145e1565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb61342f565b611003613445565b906064359067ffffffffffffffff821161063957366023830112156106395781600401359284611032856135de565b9361104060405195866135bc565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a4f565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613cce565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a461342f565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135bc565b60405191829160208352602083019061340a565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613cce565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613eae565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138bb565b956114cc60405197886135bc565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138bb565b9261150360405194856135bc565b808452601f19611512826138bb565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bc6565b51511664ffffffffff80602061154d85613bc6565b510151168601166040519161156183613567565b8252602082015261157186613bc6565b5261157b85613bc6565b5060015b8281106116555750505061159584600401613a2e565b906115a260248601613a2e565b906115af6044870161395c565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a42565b948161160260a48c01613a42565b976040519d8e613536565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613909565b610100820152613f08565b604051908152f35b806001600160801b0361166a60019385613bd3565b51511664ffffffffff8060206116835f1986018c613bd3565b510151168160206116948689613bd3565b510151160116604051916116a783613567565b825260208201526116b88289613bd3565b526116c38188613bd3565b500161157f565b6020906040516116d981613567565b5f81525f8382015282828901015201611515565b60206040916116fc36856138d3565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d81613583565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135a0565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c1615158952016139fc565b6101208c019081526118818a613cce565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c613583565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b0198895261195490613988565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce916134da565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134a9565b90611a96613eae565b82915b808310611aa4578380f35b611aaf838284613938565b3592611ab9613eae565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613be7565b908086526009602052611b5d600260408820016139fc565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613630565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b858861488a565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135bc565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a60205220613988565b6040519182916020835260208301906134da565b50346104d65760203660031901126104d65760043590611e79613eae565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613cce565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135bc565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65761217661342f565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f061342f565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613b93565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d65760043590612287613970565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d983613567565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134a9565b9060243567ffffffffffffffff8111610639576123549036906004016134a9565b9261235d613eae565b83810361276357845b818110612371578580f35b61237c818386613938565b35612388828487613938565b35875260036020526001600160a01b03604088205416906123b26123ad848988613938565b61395c565b6123ba613eae565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614706565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61472c565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c0600260408920016139fc565b6001600160801b036124e48160208401511692826040818351169201511690613630565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461253681868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135bc565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135bc565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b50612712846145e1565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614653565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613cce565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613eae565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c8816145e1565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b3661346f565b9060405192612a6b6020856135bc565b858452613a4f565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613eae565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613be7565b90805f526009602052612b86600260405f20016139fc565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613630565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b858861488a565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135bc565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613eae565b604051612e2081613536565b612e2c8260040161345b565b8152612e3a6024830161345b565b6020820152612e4b604483016135fa565b604082015260648201356001600160a01b0381168103612d51576060820152612e7660848301613529565b6080820152612e8760a48301613529565b60a0820152612e9860c483016138a9565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138bb565b90612edc60405192836135bc565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e0840152610104369101613909565b6020604091612f2c36896138d3565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f823661346f565b91613664565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613cce565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613be7565b90613630565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa61342f565b60243561310681613b93565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d5157602061225860043561360e565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135bc565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f80ac58cd00000000000000000000000000000000000000000000000000000000602093149081156133bf575b8115613395575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361338e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613387565b5f5b8381106133fa5750505f910152565b81810151838201526020016133eb565b90602091613423815180928185528580860191016133e9565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b8181106134f75750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134ea565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761355357604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761355357604052565b610180810190811067ffffffffffffffff82111761355357604052565b6060810190811067ffffffffffffffff82111761355357604052565b90601f8019910116810190811067ffffffffffffffff82111761355357604052565b67ffffffffffffffff811161355357601f01601f191660200190565b35906001600160801b0382168203612d5157565b61361781613b93565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161365057565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b0316801561389657815f5260036020526001600160a01b0360405f20541615158061388e575b80613871575b61385e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137a9575b6001600160a01b03935085613772575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361375a57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613791825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136f9565b9192905080613807575b156137c0578282916136e9565b82846137d857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613835575b806137b35750825f526005602052336001600160a01b0360405f205416146137b3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613812565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615613699565b506001613693565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135535760051b60200190565b9190826040910312612d51576040516138eb81613567565b60206139048183956138fc816135fa565b8552016138a9565b910152565b9190826040910312612d515760405161392181613567565b602080829461392f8161345b565b84520135910152565b91908110156139485760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b6040519061397d82613567565b5f6020838281520152565b908154613994816138bb565b926139a260405194856135bc565b81845260208401905f5260205f205f915b8383106139c05750505050565b6001602081926040516139d281613567565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139b3565b90604051613a09816135a0565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a5b838284613664565b803b613a68575b50505050565b602091613aae6001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061340a565b03815f865af15f9181613b36575b50613aea5750613aca6146d7565b80519081613ae55782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b2457505f808080613a62565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613b8b575b81613b52602093836135bc565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613abc565b3d9150613b45565b805f5260036020526001600160a01b0360405f205416908115613bb4575090565b637e27328960e01b5f5260045260245ffd5b8051156139485760200190565b80518210156139485760209160051b010190565b9064ffffffffff421691805f52600a602052613c0560405f20613988565b908364ffffffffff6020613c1885613bc6565b5101511611613cc757805f5260096020528364ffffffffff60405f205460c81c161115613ca857506001600160801b03613c5182613bc6565b515116916001925b8251841015613ca1578464ffffffffff6020613c758787613bd3565b5101511611613ca1576001600160801b0360019181613c948787613bd3565b5151160116930192613c59565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613cf05750600490565b805f52600960205260405f205460f81c613d5c57805f52600960205264ffffffffff60405f205460a01c164210613d5757613d2a81613be7565b905f5260096020526001600160801b0380600260405f200154169116105f14613d5257600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e9c575b80613e7f575b613e6d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e36575b1680613e1e575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613dda565b613e55835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613dd3565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613d87565b506001600160a01b0382161515613d81565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ee057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f2a6001600160801b03604084015116602061010085015101519061474c565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145b95780156145915781518015614569577f0000000000000000000000000000000000000000000000000000000000000000811161453e575064ffffffffff6020613f9884613bc6565b510151168110156144fa57505f905f905f81515f905b808210614472575050505064ffffffffff804216911690818110156144445750506001600160801b03169081810361441657505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061417a8751975f19890190613bd3565b51015160c81b169360a01b169116171785555f5b818110614364575050600187016007556001600160a01b036020830151168015613896576141c4886001600160a01b0392613d62565b166143385786826142126001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b038551169030903390614829565b6001600160801b0360208401511680614308575b506001600160a01b03815116946142fd6142df6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142848b613567565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134da565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614332906001600160a01b036060840151166001600160a01b036101008501515116903390614829565b5f614226565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f209061437f8160e0870151613bd3565b51825492680100000000000000008410156135535760018401808255841015613948576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161418e565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614496906001600160801b0361448d8588613bd3565b5151169061472c565b9364ffffffffff8060206144aa8685613bd3565b510151169416808511156144c657506001849301909291613fae565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061450b84613bc6565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614627575b50811561460e575090565b90506001600160a01b03614622339261360e565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614603565b805f52600960205261466a600260405f20016139fc565b90805f52600960205260ff600160405f20015460a01c165f146146985750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ba57506146b790613be7565b90565b6146b791506001600160801b036040818351169201511690613630565b3d15614701573d906146e8826135de565b916146f660405193846135bc565b82523d5f602084013e565b606090565b6146b79061471381614653565b905f526009602052600260405f20015460801c90613630565b906001600160801b03809116911601906001600160801b03821161365057565b91909160405161475b81613567565b5f81525f6020820152926001600160801b03821690811561480c5767016345785d8a000081116147d5576147976001600160801b039183614968565b16602085019181835211156147c1576001600160801b0391826147bc92511690613630565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161481d81613567565b5f81525f602082015290565b9091926001600160a01b036148889481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148836084836135bc565b6148da565b565b614888926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148836064836135bc565b5f806001600160a01b0361490393169360208151910182865af16148fc6146d7565b9083614a16565b8051908115159182614944575b50506149195750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614910565b9091905f1983820983820291828083109203918083039214614a0557670de0b6b3a76400008210156149d5577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a535750805115614a2b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a99575b614a64575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a5c56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615cfe908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614c8e565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166153f3565b9701166153f3565b9801166153f3565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614d8e565b1690614ef4565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615222565b610340516103a05190939091906105ac600161054a60646105438188066156fb565b96046153f3565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906157fc565b60b76106ed5f615aef565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156bd565b1561456e57601b60909a5b6107298c6153f3565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615aef565b98601b6028610a1a8c615bfa565b610a2384615c79565b8082111561456757505b019a6107298c6153f3565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615aef565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615aef565b9660b7610ac189615bfa565b610aca8b615c79565b8082111561455f5750995b601b8c8c019a6107298c6153f3565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614e87565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c601460226114096157c1565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c6157c1565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df607260236116646157c1565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e76157c1565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614e87565b60e05261195561194f614c18565b856156bd565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615a40565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615a40565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615aaa565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615aaa565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d906153f3565b916134a7906153f3565b906134b1906153f3565b936134bb906153f3565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b076024356153f3565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e6024356153f3565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615552565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615552565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614c53565b906156bd565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156bd565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156bd565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156bd565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ea565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c0c575b614bd05780602080614b89935183010191016147c5565b601e8151115f146148245750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b50604051614bdf604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c27604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614c62604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614d7a5760048103614ca85750614824614c53565b60038103614cec5750604051614cbf604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d305750604051614d03604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d3f57614824614c18565b604051614d4d604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614dcb602482614713565b51915afa614dd7614796565b9080614e06575b15614e01576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614dde565b60405190614e20604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614e5b604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eb29493614ee36020614ef295614ed5828096816040519c8d8b83829d519485930191016146cd565b8901614ec6825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b9081156151e557806151d557505b806001811015614f6b575050614f16614e4c565b6148246002602060405184614f3482965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c680001115615177576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614fa78482614713565b5f815281526040918251614fbb8482614713565b600181527f4b0000000000000000000000000000000000000000000000000000000000000085820152848301528251614ff48482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161502d8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150678482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561515d578451946150b18187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061514a5750507f2000000000000000000000000000000000000000000000000000000000000000602786015250600884526151319061512b90615126602887614713565b6153f3565b916156fb565b916005851015614b25576148249460051b015192614e87565b81810183015187820184015282016150de565b9490915060016103e86064600a850406930491019461509a565b50615180614e11565b614824600860206040518461519e82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f02565b50506040516151f5604082614713565b600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b620151809103048061528c5750615237614e4c565b614824600660206040518461525582965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f8111615363576001810361531f576148246152e16040516152b1604082614713565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926153f3565b602060405193826152fb86945180928580880191016146cd565b830161530f825180938580850191016146cd565b010103601f198101835282614713565b6148246152e1604051615333604082614713565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926153f3565b5061536c614e11565b614824600a60206040518461538a82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153cb8261477a565b6153d86040519182614713565b82815280926153e9601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561552a575b806d04ee2d6d415b85acef8100000000600a92101561550f575b662386f26fc100008110156154fb575b6305f5e1008110156154ea575b6127108110156154db575b60648110156154cd575b10156154c2575b600a602161547d600185016153c1565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154bd57600a9091615482565b505090565b60019091019061546d565b606460029104930192615466565b6127106004910493019261545c565b6305f5e10060089104930192615451565b662386f26fc1000060109104930192615444565b6d04ee2d6d415b85acef810000000060209104930192615434565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461541a565b908151156156a75760405191615569606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576155ff9060021b6153c1565b90602082019080815182019560208701908151925f83525b88811061565957505060039394959650525106806001146156475760021461563d575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c1687010151600285015316840101516003820153019497615617565b90506040516156b7602082614713565b5f815290565b90815181519081811493846156d4575b5050505090565b602092939450820120920120145f8080806156cd565b908151811015614b25570160200190565b8061570f57506040516156b7602082614713565b600a81101561577557615721906153f3565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261576481518092602086860191016146cd565b81010301601f198101835282614713565b61577e906153f3565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261576481518092602086860191016146cd565b604051906157d0604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615a305761580a6157c1565b9061271003906127108211614b1157602e606191605061582c614824956153f3565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f8701526158b9815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c82015261594082518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d2200000000000000000000000000000000000060708201526159a1825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156b7602082614713565b6010614ef29193929360206040519582615a6388945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615a9982518093856030850191016146cd565b01010301601f198101845283614713565b6005614ef29193929360206040519582615acd88945180928580880191016146cd565b830164010714051160dd1b83820152615a9982518093856025850191016146cd565b6004811015614d7a5780615b395750604051615b0c604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615b7d5750604051615b50604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615bbf57604051615b92604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615bcd604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f9080518015615c725790600d915f925f925b828410615c205750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615c5488856156ea565b511614615c6a575b820194600101929190615c0d565b859450615c5c565b5050505f90565b5f9080518015615c7257906010915f925f925b828410615c9f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615cd388856156ea565b511614615ce9575b820194600101929190615c8c565b859450615cdb56fea164736f6c634300081a000a"; + hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601781527f4e6f6e2d416c7068616e756d657269632053796d626f6c000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 61acdb0d9..7535afac1 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -302,6 +302,28 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { return string.concat("Sablier V2 ", sablierModel, " #", streamId); } + /// @notice Checks whether the provided string contains only alphanumeric characters and spaces. + /// @dev Note that this returns true for empty strings, but it is not a security concern. + function isAlphanumeric(string memory str) internal pure returns (bool) { + // Convert the string to bytes to iterate over its characters. + bytes memory b = bytes(str); + + uint256 length = b.length; + for (uint256 i = 0; i < length; ++i) { + bytes1 char = b[i]; + + // Check if it's a space or an alphanumeric character. + bool isSpace = char == 0x20; // space + bool isDigit = char >= 0x30 && char <= 0x39; // 0-9 + bool isUppercaseLetter = char >= 0x41 && char <= 0x5A; // A-Z + bool isLowercaseLetter = char >= 0x61 && char <= 0x7A; // a-z + if (!(isSpace || isDigit || isUppercaseLetter || isLowercaseLetter)) { + return false; + } + } + return true; + } + /// @notice Maps ERC-721 symbols to human-readable model names. /// @dev Reverts if the symbol is unknown. function mapSymbol(IERC721Metadata sablier) internal view returns (string memory) { @@ -341,11 +363,14 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { string memory symbol = abi.decode(returnData, (string)); - // The length check is a precautionary measure to help mitigate potential security threats from malicious assets - // injecting scripts in the symbol string. + // Check if the symbol is too long or contains non-alphanumeric characters, this measure helps mitigate + // potential security threats from malicious assets injecting scripts in the symbol string. if (bytes(symbol).length > 30) { return "Long Symbol"; } else { + if (!isAlphanumeric(symbol)) { + return "Non-Alphanumeric Symbol"; + } return symbol; } } diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index c643f5cf3..442e7be59 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { +contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_GenerateAccentColor() external view { // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol b/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol new file mode 100644 index 000000000..7c24e44d5 --- /dev/null +++ b/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; + +contract IsAlphanumeric_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { + function test_IsAlphanumeric_EmptyString() external view { + string memory symbol = ""; + bool result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + } + + modifier whenNotEmptyString() { + _; + } + + function test_IsAlphanumeric_ContainsNonAlphanumericCharacters() external view whenNotEmptyString { + string memory symbol = ""; + bool result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo/"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo\\"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo%"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo&"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo("; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo)"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo\""; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo'"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo`"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo;"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + + symbol = "foo%20"; // URL-encoded empty space + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertFalse(result, "isAlphanumeric"); + } + + modifier whenOnlyAlphanumericCharacters() { + _; + } + + function test_IsAlphanumeric() external view whenNotEmptyString whenOnlyAlphanumericCharacters { + string memory symbol = "foo"; + bool result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = "Foo"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = "Foo "; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = "Foo Bar"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = " "; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = "foo01234"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + + symbol = "123456789"; + result = nftDescriptorMock.isAlphanumeric_(symbol); + assertTrue(result, "isAlphanumeric"); + } +} diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree b/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree new file mode 100644 index 000000000..c02ab1f10 --- /dev/null +++ b/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree @@ -0,0 +1,8 @@ +isAlphanumeric.t.sol +├── when the symbol is an empty string +│ └── it should return true +└── when the symbol is not an empty string + ├── given the symbol does not contain only alphanumeric characters + │ └── it should return false + └── given the symbol contains only alphanumeric characters + └── it should return true diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 07461069b..e023c8e6b 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -6,9 +6,9 @@ import { MockERC721 } from "forge-std/src/mocks/MockERC721.sol"; import { Errors } from "src/libraries/Errors.sol"; -import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { +contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_RevertGiven_UnknownNFT() external { MockERC721 nft = new MockERC721(); nft.initialize("Foo", "FOO"); diff --git a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol index 98bbd036b..70e4677a6 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract SafeAssetDecimals_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { +contract SafeAssetDecimals_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_SafeAssetDecimals_EOA() external view { address eoa = vm.addr({ privateKey: 1 }); uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(eoa)); diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index 7524ae278..7238f0a29 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ERC20Mock } from "../../../../mocks/erc20/ERC20Mock.sol"; import { ERC20Bytes32 } from "../../../../mocks/erc20/ERC20Bytes32.sol"; -import { NFTDescriptor_Integration_Concrete_Test } from "../NFTDescriptor.t.sol"; +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Concrete_Test { +contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_SafeAssetSymbol_EOA() external view { address eoa = vm.addr({ privateKey: 1 }); string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(eoa)); @@ -48,7 +48,25 @@ contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_ _; } - function test_SafeAssetSymbol() external view whenERC20Contract givenSymbolString givenSymbolNotLong { + function test_SafeAssetSymbol_NonAlphanumeric() external whenERC20Contract givenSymbolString givenSymbolNotLong { + ERC20Mock asset = new ERC20Mock({ name: "Token", symbol: "" }); + string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset)); + string memory expectedSymbol = "Non-Alphanumeric Symbol"; + assertEq(actualSymbol, expectedSymbol, "symbol"); + } + + modifier givenSymbolAlphanumeric() { + _; + } + + function test_SafeAssetSymbol() + external + view + whenERC20Contract + givenSymbolString + givenSymbolNotLong + givenSymbolAlphanumeric + { string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(dai)); string memory expectedSymbol = dai.symbol(); assertEq(actualSymbol, expectedSymbol, "symbol"); diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree index 792667a10..9082ee03b 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree @@ -8,4 +8,7 @@ safeAssetSymbol.t.sol ├── given the symbol is longer than 30 characters │ └── it should return a hard-coded values └── given the symbol is not longer than 30 characters - └── it should return the correct symbol value + ├── given the symbol contains non-alphanumeric characters + │ └── it should return a hard-coded value + └── given the symbol contains only alphanumeric characters + └── it should return the correct symbol value diff --git a/test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol b/test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol new file mode 100644 index 000000000..e16a18529 --- /dev/null +++ b/test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; + +contract IsAlphanumeric_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { + bytes1 internal constant SPACE = 0x20; // ASCII 32 + bytes1 internal constant ZERO = 0x30; // ASCII 48 + bytes1 internal constant NINE = 0x39; // ASCII 57 + bytes1 internal constant A = 0x41; // ASCII 65 + bytes1 internal constant Z = 0x5A; // ASCII 90 + bytes1 internal constant a = 0x61; // ASCII 97 + bytes1 internal constant z = 0x7A; // ASCII 122 + + modifier whenNotEmptyString() { + _; + } + + /// @dev Given enough fuzz runs, all the following scenarios will be fuzzed: + /// + /// - String with only alphanumerical characters + /// - String with only non-alphanumerical characters + /// - String with both alphanumerical and non-alphanumerical characters + function testFuzz_IsAlphanumeric(string memory symbol) external view whenNotEmptyString { + bytes memory b = bytes(symbol); + uint256 length = b.length; + bool expectedResult = true; + for (uint256 i = 0; i < length; ++i) { + bytes1 char = b[i]; + if (!isAlphanumericChar(char)) { + expectedResult = false; + break; + } + } + bool actualResult = nftDescriptorMock.isAlphanumeric_(symbol); + assertEq(actualResult, expectedResult, "isAlphanumeric"); + } + + function isAlphanumericChar(bytes1 char) internal pure returns (bool) { + bool isSpace = char == SPACE; + bool isDigit = char >= ZERO && char <= NINE; + bool isUppercaseLetter = char >= A && char <= Z; + bool isLowercaseLetter = char >= a && char <= z; + return isSpace || isDigit || isUppercaseLetter || isLowercaseLetter; + } +} diff --git a/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/integration/shared/nft-descriptor/NFTDescriptor.t.sol similarity index 91% rename from test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol rename to test/integration/shared/nft-descriptor/NFTDescriptor.t.sol index 88e972891..d7dd5099f 100644 --- a/test/integration/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/integration/shared/nft-descriptor/NFTDescriptor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "../../Integration.t.sol"; import { NFTDescriptorMock } from "../../../mocks/NFTDescriptorMock.sol"; -abstract contract NFTDescriptor_Integration_Concrete_Test is Integration_Test { +abstract contract NFTDescriptor_Integration_Shared_Test is Integration_Test { NFTDescriptorMock internal nftDescriptorMock; function setUp() public virtual override { diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index adac6ec55..a5b7176ae 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -78,6 +78,10 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { return SVGElements.hourglass(status); } + function isAlphanumeric_(string memory symbol) external pure returns (bool) { + return isAlphanumeric(symbol); + } + function mapSymbol_(IERC721Metadata nft) external view returns (string memory) { return mapSymbol(nft); } From c5e7ca83d92b875f619f2ab5647c809de502e1f7 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 18 Jun 2024 16:18:59 +0100 Subject: [PATCH 117/132] feat: eip-4906 interface (#946) * test: eip4906 interface * feat: eip4906 interface * doc: eip4906 interface --- precompiles/Precompiles.sol | 6 +++--- src/abstracts/SablierV2Lockup.sol | 6 ++++++ test/integration/concrete/lockup-dynamic/constructor.t.sol | 3 +++ test/integration/concrete/lockup-linear/constructor.t.sol | 3 +++ test/integration/concrete/lockup-tranched/constructor.t.sol | 3 +++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 5c230310a..b7040ede5 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,11 +26,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e4576158d66060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260016007556154c8908161040e8239608051816137b2015260a051818181610bdd015261387c0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461274857508063027b67441461272657806306fdde0314612632578063081812fc14612614578063095ea7b31461250f5780631400ecec1461245e5780631c1cdd4c146123d55780631e99d569146123b857806323b872dd1461239f57806331df3d481461228c57806340e58ee514611f65578063425d30dd14611f1357806342842e0e14611ee957806342966c6814611d0c5780634426757014611ce55780634857501f14611c5b5780634869e12d14611c1f5780634cc55e1114611b2657806354c022921461187057806357404b12146117d85780636352211e146117a85780636d0cee75146117a857806370a082311461173d57806375829def146116cb5780637cad6cd1146115bf5780637de6b1db146113bf5780638659c27014611021578063894e9a0d14610cec5780638f69b99314610c515780639067b67714610c005780639188ec8414610bc557806395d89b4114610ab8578063a22cb46514610a02578063a80fc071146109af578063ad35efd41461093c578063b2564569146108ea578063b637b8651461088e578063b88d4fde14610800578063b8a3be66146107cb578063b971302a1461077b578063bc2be1be1461072a578063c156a11d14610605578063c87b56dd146104e9578063d4dbd20b14610496578063d511609f14610449578063d975dfed146103fc578063e985e9c5146103a9578063ea5ead191461037a578063eac8f5b814610327578063f590c176146102ca578063f851a440146102a45763fdd46d601461025a575f80fd5b346102a15760603660031901126102a157610273612873565b6044356001600160801b038116810361029d5761029a916102926137a8565b600435613476565b80f35b8280fd5b80fd5b50346102a157806003193601126102a1576001600160a01b036020915416604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760016040826020946001600160a01b0394526009855220015416604051908152f35b50346102a15760403660031901126102a15761029a60043561039a612873565b6103a382614083565b91613079565b50346102a15760403660031901126102a1576001600160a01b0360406103cd61285d565b92826103d7612873565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883614083565b6001600160801b0360405191168152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081602093600293526009845220015460801c604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760036040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760203660031901126102a15760043561050781613506565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9081156105fa578291610577575b6040516020808252819061057390820185612838565b0390f35b90503d8083833e6105888183612a0a565b81019060208183031261029d5780519067ffffffffffffffff82116105f6570181601f8201121561029d578051926105bf84612a2c565b926105cd6040519485612a0a565b848452602085840101116102a15750610573926105f09160208085019101612817565b5f61055d565b8380fd5b6040513d84823e3d90fd5b50346102a15760403660031901126102a15760043590610623612873565b9161062c6137a8565b808252600960205260ff600160408420015460a81c161561071857805f5260036020526001600160a01b0360405f205416928333036107005761066e82614083565b6001600160801b0381166106ef575b506001600160a01b038116156106dc5761069f826001600160a01b039261365c565b16806106b85760248383637e27328960e01b8252600452fd5b908382036106c4578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b6106fa908584613079565b5f61067d565b63216caf0d60e01b8352600482905233602452604483fd5b6024925062b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c1615610316576040816020936001600160a01b03935260098452205416604051908152f35b50346102a15760203660031901126102a15760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346102a15760803660031901126102a15761081a61285d565b610822612873565b906064359067ffffffffffffffff82116105f657366023830112156105f6578160040135928461085185612a2c565b9361085f6040519586612a0a565b858552366024878301011161088a578561029a96602460209301838801378501015260443591612f35565b5080fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081610573936108d69352600a60205220612eae565b604051918291602083526020830190612908565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460b01c166040519015158152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610975906135c8565b60405190600581101561098a57602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760026040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760403660031901126102a157610a1c61285d565b6024359081151580920361029d576001600160a01b0316908115610a8c57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346102a157806003193601126102a1576040519080600254908160011c91600181168015610bbb575b602084108114610ba757838652908115610b805750600114610b23575b61057384610b0f81860382612a0a565b604051918291602083526020830190612838565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610b6657509091508101602001610b0f82610aff565b919260018160209254838588010152019101909291610b4d565b60ff191660208087019190915292151560051b85019092019250610b0f9150839050610aff565b602483634e487b7160e01b81526022600452fd5b92607f1692610ae2565b50346102a157806003193601126102a15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610c8a906135c8565b9060058210159081610ccb5760028314918215610cdf575b8215610cb6575b6020836040519015158152f35b909150610ccb57506004602091145f80610ca9565b80634e487b7160e01b602492526021600452fd5b5060038314915080610ca2565b50346102a15760203660031901126102a15760043590604051610180810181811067ffffffffffffffff82111761100d576060916101609160405283815283602082015283604082015283838201528360808201528360a08201528360c08201528360e08201528361010082015283610120820152610d69612e5e565b6101408201520152818152600960205260ff600160408320015460a81c161561031657815f52600960205260405f2060405190610da5826129ed565b8054916001600160a01b0383168152602081019364ffffffffff8460a01c168552604082019264ffffffffff8560c81c168452606083019360ff8660f01c1615158552608084019560f81c1515865260018201549260a08501956001600160a01b038516875260c086019060ff8660a01c1615158252610e46600260e089019660ff8960a81c161515885260ff6101008b019960b01c161515895201612e7c565b61012088019081526002610e598d6135c8565b610e628161297a565b14611005575b5197516001600160a01b0316935164ffffffffff1690511515915115159451151595511515968b5f52600360205260405f20546001600160a01b03169b8452600a6020526040842090516001600160a01b03169a5164ffffffffff169951151593506040519a610eda6101808d612a0a565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610f2e90612eae565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057391612908565b838252610e68565b602483634e487b7160e01b81526041600452fd5b50346102a15760203660031901126102a15760043567ffffffffffffffff811161088a576110539036906004016128d7565b9061105c6137a8565b82915b80831061106a578380f35b611075838284612ded565b359261107f6137a8565b835f52600960205260ff600160405f20015460a81c16156113ac578385526009602052604085206001015460a01c60ff16156110c85760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c61139a576110fd815f5260096020526001600160a01b0360405f205416331490565b156113845761110b81613539565b90805f526009602052611123600260405f2001612e7c565b916001600160801b038351166001600160801b038216101561137157815f52600960205260ff60405f205460f01c161561135e579061117a826001600160801b036020818796818d99511603169501511690612a7e565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215611339575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506112966001600160a01b03600160405f200154169461126e8b85886144dd565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6112da575b505050505050600101919061105f565b813b1561133557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161131d575b808080806112ca565b9061132791612a0a565b835f126105f657835f611314565b8580fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556111c4565b506339c6dc7360e21b8652600452602485fd5b506322cad1af60e11b8652600452602485fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b838562b8e7e760e51b8152602491600452fd5b50346102a15760203660031901126102a157600435906113dd6137a8565b818152600960205260ff600160408320015460a81c161561031657611401826135c8565b61140a8161297a565b600481036114255750602491634a5541ef60e01b8252600452fd5b61142e8161297a565b60038103611449575060249163fe19f19f60e01b8252600452fd5b6002906114558161297a565b146115ad57611478825f5260096020526001600160a01b0360405f205416331490565b1561158e57818152600960205260ff604082205460f01c161561157c57818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a1805f5260036020526001600160a01b0360405f20541690813b61151e575050f35b813b156115785782916024839260405195869384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611565579050f35b61156e91612a0a565b805f126102a15780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b82526004526001600160a01b033316602452fd5b6024916322cad1af60e11b8252600452fd5b50346102a15760203660031901126102a1576004356001600160a01b03811680910361088a576001600160a01b0382541633810361169c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116885760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346102a15760203660031901126102a1576116e561285d565b9080546001600160a01b03811633810361169c57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346102a15760203660031901126102a1576001600160a01b0361175f61285d565b16801561177c578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346102a15760203660031901126102a15760206117c7600435613506565b6001600160a01b0360405191168152f35b50346102a15760203660031901126102a157600435906117f6612e46565b50818152600960205260ff600160408320015460a81c1615610316579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c16825191611848836129d1565b8252602082015261186e8251809264ffffffffff60208092828151168552015116910152565bf35b50346102a15760203660031901126102a1576004359067ffffffffffffffff82116102a15781360361012060031982011261088a576118ad6137a8565b60c4830135906022190181121561088a57820160048101359067ffffffffffffffff821161029d5760240190606081023603821361029d57906118f1913691612d21565b8051916118fd83612d09565b9261190b6040519485612a0a565b808452601f1961191a82612d09565b01825b818110611b0f57505064ffffffffff4216926001600160801b0361194082613802565b51511667ffffffffffffffff602061195784613802565b5101511664ffffffffff80604061196d86613802565b510151168701169060405192611982846129b5565b83526020830152604082015261199786613802565b526119a185613802565b5060015b828110611a7b575050506119bb84600401612e25565b906119c860248601612e25565b906119d560448701612e11565b6064870135916001600160a01b0383168093036102a1576020611a73611a33611a688b8b8b8b8b8b6001600160801b038c6001600160a01b03611a1a60848a01612e39565b9481611a2860a48c01612e39565b976040519d8e612984565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612dbe565b610100820152613823565b604051908152f35b806001600160801b03611a906001938561380f565b51511667ffffffffffffffff6020611aa8848761380f565b5101511664ffffffffff806040611ac25f1987018d61380f565b51015116816040611ad3878a61380f565b5101511601169060405192611ae7846129b5565b835260208301526040820152611afd828961380f565b52611b08818861380f565b50016119a5565b602090611b1a612e5e565b8282890101520161191d565b50346102a15760403660031901126102a15760043567ffffffffffffffff811161088a57611b589036906004016128d7565b9060243567ffffffffffffffff81116105f657611b799036906004016128d7565b611b816137a8565b808403611bef57845b848110611b95578580f35b80611be9611ba66001938888612ded565b35611bb2838989612ded565b35895260036020526001600160a01b0360408a205416611bdb611bd685888a612ded565b612e11565b91611be46137a8565b613476565b01611b8a565b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883613fd3565b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c16156103165780611c96836135c8565b926005841015611cd157600260209403611cb7575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80611cab565b602482634e487b7160e01b81526021600452fd5b50346102a157806003193601126102a15760206001600160a01b0360085416604051908152f35b50346102a15760203660031901126102a157600435611d296137a8565b808252600960205260ff600160408420015460a81c161561099e57808252600960205260ff600160408420015460a01c1615611ebe57611d6881613f61565b15611ea85780825260036020526001600160a01b03604083205416151580611ea1575b80611e84575b611e72577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b036040832054168015908115611e3b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611e29575080f35b637e27328960e01b8252600452602490fd5b611e5a835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f19019055611ddf565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c1615611d91565b5081611d8b565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346102a15761029a611efb3661289d565b9060405192611f0b602085612a0a565b858452612f35565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460a01c166040519015158152f35b50346121fa5760203660031901126121fa5760043590611f836137a8565b815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c165f14611fcd5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c61226857612000815f5260096020526001600160a01b0360405f205416331490565b156122495761200e81613539565b90805f526009602052612026600260405f2001612e7c565b916001600160801b038351166001600160801b038216101561223657815f52600960205260ff60405f205460f01c161561222357806001600160801b0360208161207a948188511603169501511690612a7e565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b038116919082156121fe575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061216e6001600160a01b03600160405f200154169461126e8b85886144dd565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6121a5578580f35b813b156121fa575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e7575b808080808580f35b6121f391505f90612a0a565b5f806121df565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556120c4565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa5760043567ffffffffffffffff81116121fa5761014060031982360301126121fa576122c66137a8565b604051906122d382612984565b6122df81600401612889565b82526122ed60248201612889565b60208301526122fe60448201612a48565b604083015260648101356001600160a01b03811681036121fa5760608301526123296084820161296d565b608083015261233a60a4820161296d565b60a083015261234b60c48201612cf7565b60c083015260e481013567ffffffffffffffff81116121fa57810191366023840112156121fa57611a68611a739261238f6020953690602460048201359101612d21565b60e0840152610104369101612dbe565b346121fa576123b66123b03661289d565b91612ab2565b005b346121fa575f3660031901126121fa576020600754604051908152f35b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d5761240d906135c8565b600581101561243957806020911590811561242e575b506040519015158152f35b600191501482612423565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d576020905f90805f526009835260ff60405f205460f01c16806124f3575b6124c1575b506001600160801b0360405191168152f35b6124ed9150805f52600983526124e76001600160801b03600260405f2001541691613539565b90612a7e565b826124af565b50805f526009835260ff600160405f20015460a01c16156124aa565b346121fa5760403660031901126121fa5761252861285d565b60243561253481613506565b33151580612601575b806125ce575b6125a25781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612543565b50336001600160a01b038216141561253d565b346121fa5760203660031901126121fa5760206117c7600435612a5c565b346121fa575f3660031901126121fa576040515f6001548060011c9060018116801561271c575b602083108114612708578285529081156126e45750600114612686575b61057383610b0f81850382612a0a565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106126ca57509091508101602001610b0f612676565b9192600181602092548385880101520191019092916126b2565b60ff191660208086019190915291151560051b84019091019150610b0f9050612676565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612659565b346121fa575f3660031901126121fa57602060405167016345785d8a00008152f35b346121fa5760203660031901126121fa57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036121fa57817f80ac58cd00000000000000000000000000000000000000000000000000000000602093149081156127ed575b81156127c3575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836127bc565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506127b5565b5f5b8381106128285750505f910152565b8181015183820152602001612819565b9060209161285181518092818552858086019101612817565b601f01601f1916010190565b600435906001600160a01b03821682036121fa57565b602435906001600160a01b03821682036121fa57565b35906001600160a01b03821682036121fa57565b60609060031901126121fa576004356001600160a01b03811681036121fa57906024356001600160a01b03811681036121fa579060443590565b9181601f840112156121fa5782359167ffffffffffffffff83116121fa576020808501948460051b0101116121fa57565b90602080835192838152019201905f5b8181106129255750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612918565b359081151582036121fa57565b6005111561243957565b610120810190811067ffffffffffffffff8211176129a157604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176129a157604052565b6040810190811067ffffffffffffffff8211176129a157604052565b610140810190811067ffffffffffffffff8211176129a157604052565b90601f8019910116810190811067ffffffffffffffff8211176129a157604052565b67ffffffffffffffff81116129a157601f01601f191660200190565b35906001600160801b03821682036121fa57565b612a6581613506565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b038211612a9e57565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b03168015612ce457815f5260036020526001600160a01b0360405f205416151580612cdc575b80612cbf575b612cac577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612bf7575b6001600160a01b03935085612bc0575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612ba857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612bdf825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b47565b9192905080612c55575b15612c0e57828291612b37565b8284612c2657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612c83575b80612c015750825f526005602052336001600160a01b0360405f20541614612c01565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c60565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615612ae7565b506001612ae1565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff821682036121fa57565b67ffffffffffffffff81116129a15760051b60200190565b929192612d2d82612d09565b93612d3b6040519586612a0a565b60606020868581520193028201918183116121fa57925b828410612d5f5750505050565b6060848303126121fa5760405190612d76826129b5565b612d7f85612a48565b825260208501359067ffffffffffffffff821682036121fa5782602092836060950152612dae60408801612cf7565b6040820152815201930192612d52565b91908260409103126121fa57604051612dd6816129d1565b6020808294612de481612889565b84520135910152565b9190811015612dfd5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036121fa5790565b356001600160a01b03811681036121fa5790565b3580151581036121fa5790565b60405190612e53826129d1565b5f6020838281520152565b60405190612e6b826129b5565b5f6040838281528260208201520152565b90604051612e89816129b5565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612eba81612d09565b92612ec86040519485612a0a565b81845260208401905f5260205f205f915b838310612ee65750505050565b600160208192604051612ef8816129b5565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612ed9565b90612f41838284612ab2565b803b612f4e575b50505050565b602091612f946001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190612838565b03815f865af15f918161301c575b50612fd05750612fb0614054565b80519081612fcb5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361300a57505f808080612f48565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613071575b8161303860209383612a0a565b810103126121fa57517fffffffff00000000000000000000000000000000000000000000000000000000811681036121fa57905f612fa2565b3d915061302b565b9190916130846137a8565b805f52600960205260ff600160405f20015460a81c161561244d575f92815f52600960205260ff600160405f20015460a01c16613463576001600160a01b038116918215613438576001600160801b038416801561340c57815f5260036020526001600160a01b0360405f2054169081851415806133fc575b6133c8576001600160801b0361311284614083565b168082116133955750825f5260096020526001600160a01b0360405f20541694835f52600960205261314e87600260405f20015460801c6140a9565b5f85815260096020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561319190612e7c565b6001600160801b036131b58160208401511692826040818351169201511690612a7e565b161115613363575b835f526009602052837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160405f2001541694613206818a886144dd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a18033141580613359575b6132f1575b8333141590816132e6575b816132db575b50613264575b5050505050565b823b156132d757604051636fd110e960e01b815260048101919091523360248201526001600160a01b0390911660448201526001600160801b039092166064830152829082908183816084810103925af16132c2575b80808061325d565b6132cd828092612a0a565b6102a157806132ba565b8480fd5b90508314155f613257565b843b15159150613251565b803b156121fa57604051636fd110e960e01b8152600481018390523360248201526001600160a01b03841660448201526001600160801b03861660648201525f8160848183865af1613344575b50613246565b6133519196505f90612a0a565b5f945f61333e565b50803b1515613241565b5f84815260096020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131bd565b90837fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b84837fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061340683613f61565b156130fd565b507fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b9190915f92815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c16613463576001600160a01b038116918215613438576001600160801b038416801561340c57815f5260036020526001600160a01b0360405f2054169081851415806133fc576133c8576001600160801b0361311284614083565b805f5260036020526001600160a01b0360405f205416908115613527575090565b637e27328960e01b5f5260045260245ffd5b64ffffffffff4216815f5260096020528064ffffffffff60405f205460a01c1610156135c257815f52600960205264ffffffffff60405f205460c81c1611156135a757805f52600a602052600160405f2054115f1461359e5761359b90614189565b90565b61359b906140c9565b5f5260096020526001600160801b03600260405f2001541690565b50505f90565b805f52600960205260ff600160405f20015460a01c165f146135ea5750600490565b805f52600960205260405f205460f81c61365657805f52600960205264ffffffffff60405f205460a01c1642106136515761362481613539565b905f5260096020526001600160801b0380600260405f200154169116105f1461364c57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613796575b80613779575b613767577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613730575b1680613718575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556136d4565b61374f835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556136cd565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613681565b506001600160a01b038216151561367b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036137da57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612dfd5760200190565b8051821015612dfd5760209160051b010190565b906138456001600160801b03604084015116602061010085015101519061439f565b916001600160801b038351169060e08101519160c082019264ffffffffff8451168215613f39578015613f115781518015613ee9577f00000000000000000000000000000000000000000000000000000000000000008111613ebe575064ffffffffff60406138b384613802565b51015116811015613e7a57505f905f905f81515f905b808210613df2575050505064ffffffffff80421691169081811015613dc45750506001600160801b031690818103613d9657505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613a9e8751975f1989019061380f565b51015160c81b169360a01b169116171785555f5b818110613c88575050600187016007556001600160a01b036020830151168015612ce457613ae8886001600160a01b039261365c565b16613c5c578682613b366001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b03855116903090339061447c565b6001600160801b0360208401511680613c2c575b506001600160a01b0381511694613c21613c036001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613ba88b6129d1565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612908565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613c56906001600160a01b036060840151166001600160a01b03610100850151511690339061447c565b5f613b4a565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f2090613ca38160e087015161380f565b518254680100000000000000008110156129a15760018101808555811015612dfd576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613ab2565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613e16906001600160801b03613e0d858861380f565b515116906140a9565b9364ffffffffff806040613e2a868561380f565b51015116941680851115613e46575060018493019092916138c9565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613e8b84613802565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613fa7575b508115613f8e575090565b90506001600160a01b03613fa23392612a5c565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613f83565b805f526009602052613fea600260405f2001612e7c565b90805f52600960205260ff600160405f20015460a01c165f146140185750602001516001600160801b031690565b90815f52600960205260405f205460f81c614037575061359b90613539565b61359b91506001600160801b036040818351169201511690612a7e565b3d1561407e573d9061406582612a2c565b916140736040519384612a0a565b82523d5f602084013e565b606090565b61359b9061409081613fd3565b905f526009602052600260405f20015460801c90612a7e565b906001600160801b03809116911601906001600160801b038211612a9e57565b5f818152600960205260409020546141009064ffffffffff60a082901c811660c89290921c8116829003811691428216031661452d565b90805f52600a60205260405f20805415612dfd575f5261415567ffffffffffffffff60205f205460801c1692825f5260096020526141506001600160801b03600260405f2001541694859261460d565b614680565b918213614172575061416e6001600160801b039161475b565b1690565b90505f526009602052600260405f20015460801c90565b9064ffffffffff421691805f52600960205260405f2090604051906141ad826129ed565b61012061424060028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612e7c565b92019182525f52600a60205261425860405f20612eae565b915f9264ffffffffff604061426c83613802565b510151168664ffffffffff5f925b161061436057816142f164ffffffffff9697988784816001600160801b036142a9614150986142f69b9a61380f565b5151169a8b9867ffffffffffffffff60206142c4868b61380f565b51015116978260406142d6878461380f565b510151169480614343575050511680925b031692031661452d565b61460d565b9182136143175750906001600160801b03614311819361475b565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f1461433e575090565b905090565b6040925090614355915f19019061380f565b5101511680926142e7565b936001600160801b0360019181614377888661380f565b51511601169401958064ffffffffff8060406143938b8761380f565b5101511698929861427a565b9190916040516143ae816129d1565b5f81525f6020820152926001600160801b03821690811561445f5767016345785d8a00008111614428576143ea6001600160801b039183615381565b1660208501918183521115614414576001600160801b03918261440f92511690612a7e565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614470816129d1565b5f81525f602082015290565b9091926001600160a01b036144db9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526144d6608483612a0a565b614790565b565b6144db926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526144d6606483612a0a565b600160ff1b81148015614600575b6145d8575f8112156145cf5761455f815f035b5f8412156145c857835f039061481e565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614599575f19911813156145945790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061481e565b61455f8161454e565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461453b565b80614627575061462357670de0b6b3a764000090565b5f90565b90670de0b6b3a76400008214614672578061464a575050670de0b6b3a764000090565b670de0b6b3a7640000811461466e576146699061415061359b93614924565b614a7b565b5090565b5050670de0b6b3a764000090565b600160ff1b8114801561474e575b614726575f81121561471d576146b2815f035b5f84121561471657835f0390615381565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116146e7575f19911813156145945790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390615381565b6146b2816146a1565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461468e565b5f81126147655790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b036147b993169360208151910182865af16147b2614054565b908361542f565b80519081151591826147fa575b50506147cf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126121fa57602001518015908115036121fa575f806147c6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146148e957818410156148af57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156148f6570490565b634e487b7160e01b5f52601260045260245ffd5b80156148f6576ec097ce7bc90715b34b9f10000000000590565b805f811315614a5057670de0b6b3a76400008112614a3057506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614a1d57506706f05b59d3b20000905b5f82136149e75750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614a0f575b60011d906149da565b809192019160011d90614a06565b9050670de0b6b3a7640000929150020290565b5f19915080156148f6576ec097ce7bc90715b34b9f100000000005614941565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614aa85768033dd1780914b9711419811261365157614a9f905f03614a7b565b61359b9061490a565b680a688906bd8affffff811361535657670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff000000000000008216615221575b670de0b6b3a76400009066ff0000000000008316615111575b65ff00000000008316615009575b64ff000000008316614f09575b63ff0000008316614e11575b62ff00008316614d21575b61ff008316614c39575b60ff8316614b59575b029060401c60bf031c90565b60808316614c26575b60408316614c13575b60208316614c00575b60108316614bed575b60088316614bda575b60048316614bc7575b60028316614bb4575b6001831615614b4d57680100000000000000010260401c614b4d565b680100000000000000010260401c614b98565b680100000000000000030260401c614b8f565b680100000000000000060260401c614b86565b6801000000000000000b0260401c614b7d565b680100000000000000160260401c614b74565b6801000000000000002c0260401c614b6b565b680100000000000000590260401c614b62565b6180008316614d0e575b6140008316614cfb575b6120008316614ce8575b6110008316614cd5575b6108008316614cc2575b6104008316614caf575b6102008316614c9c575b610100831615614b4457680100000000000000b10260401c614b44565b680100000000000001630260401c614c7f565b680100000000000002c60260401c614c75565b6801000000000000058c0260401c614c6b565b68010000000000000b170260401c614c61565b6801000000000000162e0260401c614c57565b68010000000000002c5d0260401c614c4d565b680100000000000058b90260401c614c43565b628000008316614dfe575b624000008316614deb575b622000008316614dd8575b621000008316614dc5575b620800008316614db2575b620400008316614d9f575b620200008316614d8c575b62010000831615614b3a576801000000000000b1720260401c614b3a565b680100000000000162e40260401c614d6e565b6801000000000002c5c80260401c614d63565b68010000000000058b910260401c614d58565b680100000000000b17210260401c614d4d565b68010000000000162e430260401c614d42565b680100000000002c5c860260401c614d37565b6801000000000058b90c0260401c614d2c565b63800000008316614ef6575b63400000008316614ee3575b63200000008316614ed0575b63100000008316614ebd575b63080000008316614eaa575b63040000008316614e97575b63020000008316614e84575b6301000000831615614b2f5768010000000000b172180260401c614b2f565b6801000000000162e4300260401c614e65565b68010000000002c5c8600260401c614e59565b680100000000058b90c00260401c614e4d565b6801000000000b17217f0260401c614e41565b680100000000162e42ff0260401c614e35565b6801000000002c5c85fe0260401c614e29565b68010000000058b90bfc0260401c614e1d565b6480000000008316614ff6575b6440000000008316614fe3575b6420000000008316614fd0575b6410000000008316614fbd575b6408000000008316614faa575b6404000000008316614f97575b6402000000008316614f84575b640100000000831615614b2357680100000000b17217f80260401c614b23565b68010000000162e42ff10260401c614f64565b680100000002c5c85fe30260401c614f57565b6801000000058b90bfce0260401c614f4a565b68010000000b17217fbb0260401c614f3d565b6801000000162e42fff00260401c614f30565b68010000002c5c8601cc0260401c614f23565b680100000058b90c0b490260401c614f16565b6580000000000083166150fe575b6540000000000083166150eb575b6520000000000083166150d8575b6510000000000083166150c5575b6508000000000083166150b2575b65040000000000831661509f575b65020000000000831661508c575b65010000000000831615614b16576801000000b1721835510260401c614b16565b680100000162e430e5a20260401c61506b565b6801000002c5c863b73f0260401c61505d565b68010000058b90cf1e6e0260401c61504f565b680100000b1721bcfc9a0260401c615041565b68010000162e43f4f8310260401c615033565b680100002c5c89d5ec6d0260401c615025565b6801000058b91b5bc9ae0260401c615017565b6680000000000000831661520e575b664000000000000083166151fb575b662000000000000083166151e8575b661000000000000083166151d5575b660800000000000083166151c2575b660400000000000083166151af575b6602000000000000831661519c575b6601000000000000831615614b085768010000b17255775c040260401c614b08565b6801000162e525ee05470260401c61517a565b68010002c5cc37da94920260401c61516b565b680100058ba01fb9f96d0260401c61515c565b6801000b175effdc76ba0260401c61514d565b680100162f3904051fa10260401c61513e565b6801002c605e2e8cec500260401c61512f565b68010058c86da1c09ea20260401c615120565b6780000000000000008216615337575b670de0b6b3a7640000906740000000000000008316615324575b6720000000000000008316615311575b67100000000000000083166152fe575b67080000000000000083166152eb575b67040000000000000083166152d8575b67020000000000000083166152c5575b67010000000000000083166152b2575b9050614aef565b680100b1afa5abcbed610260401c6152ab565b68010163da9fb33356d80260401c61529b565b680102c9a3e778060ee70260401c61528b565b6801059b0d31585743ae0260401c61527b565b68010b5586cf9890f62a0260401c61526b565b6801172b83c7d517adce0260401c61525b565b6801306fe0a31b7152df0260401c61524b565b5077b504f333f9de648480000000000000000000000000000000615231565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461541e57670de0b6b3a76400008210156153ee577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061546c575080511561544457805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806154b2575b61547d575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561547556fea164736f6c634300081a000a"; + hex"60c0604052346103e4576159096060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260016007556154fb908161040e8239608051816137e5015260a051818181610bdd01526138af0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461274857508063027b67441461272657806306fdde0314612632578063081812fc14612614578063095ea7b31461250f5780631400ecec1461245e5780631c1cdd4c146123d55780631e99d569146123b857806323b872dd1461239f57806331df3d481461228c57806340e58ee514611f65578063425d30dd14611f1357806342842e0e14611ee957806342966c6814611d0c5780634426757014611ce55780634857501f14611c5b5780634869e12d14611c1f5780634cc55e1114611b2657806354c022921461187057806357404b12146117d85780636352211e146117a85780636d0cee75146117a857806370a082311461173d57806375829def146116cb5780637cad6cd1146115bf5780637de6b1db146113bf5780638659c27014611021578063894e9a0d14610cec5780638f69b99314610c515780639067b67714610c005780639188ec8414610bc557806395d89b4114610ab8578063a22cb46514610a02578063a80fc071146109af578063ad35efd41461093c578063b2564569146108ea578063b637b8651461088e578063b88d4fde14610800578063b8a3be66146107cb578063b971302a1461077b578063bc2be1be1461072a578063c156a11d14610605578063c87b56dd146104e9578063d4dbd20b14610496578063d511609f14610449578063d975dfed146103fc578063e985e9c5146103a9578063ea5ead191461037a578063eac8f5b814610327578063f590c176146102ca578063f851a440146102a45763fdd46d601461025a575f80fd5b346102a15760603660031901126102a1576102736128a6565b6044356001600160801b038116810361029d5761029a916102926137db565b6004356134a9565b80f35b8280fd5b80fd5b50346102a157806003193601126102a1576001600160a01b036020915416604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760016040826020946001600160a01b0394526009855220015416604051908152f35b50346102a15760403660031901126102a15761029a60043561039a6128a6565b6103a3826140b6565b916130ac565b50346102a15760403660031901126102a1576001600160a01b0360406103cd612890565b92826103d76128a6565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c1615610316576020610438836140b6565b6001600160801b0360405191168152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081602093600293526009845220015460801c604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760036040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760203660031901126102a15760043561050781613539565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9081156105fa578291610577575b604051602080825281906105739082018561286b565b0390f35b90503d8083833e6105888183612a3d565b81019060208183031261029d5780519067ffffffffffffffff82116105f6570181601f8201121561029d578051926105bf84612a5f565b926105cd6040519485612a3d565b848452602085840101116102a15750610573926105f0916020808501910161284a565b5f61055d565b8380fd5b6040513d84823e3d90fd5b50346102a15760403660031901126102a157600435906106236128a6565b9161062c6137db565b808252600960205260ff600160408420015460a81c161561071857805f5260036020526001600160a01b0360405f205416928333036107005761066e826140b6565b6001600160801b0381166106ef575b506001600160a01b038116156106dc5761069f826001600160a01b039261368f565b16806106b85760248383637e27328960e01b8252600452fd5b908382036106c4578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b6106fa9085846130ac565b5f61067d565b63216caf0d60e01b8352600482905233602452604483fd5b6024925062b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c1615610316576040816020936001600160a01b03935260098452205416604051908152f35b50346102a15760203660031901126102a15760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346102a15760803660031901126102a15761081a612890565b6108226128a6565b906064359067ffffffffffffffff82116105f657366023830112156105f6578160040135928461085185612a5f565b9361085f6040519586612a3d565b858552366024878301011161088a578561029a96602460209301838801378501015260443591612f68565b5080fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081610573936108d69352600a60205220612ee1565b60405191829160208352602083019061293b565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460b01c166040519015158152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610975906135fb565b60405190600581101561098a57602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760026040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760403660031901126102a157610a1c612890565b6024359081151580920361029d576001600160a01b0316908115610a8c57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346102a157806003193601126102a1576040519080600254908160011c91600181168015610bbb575b602084108114610ba757838652908115610b805750600114610b23575b61057384610b0f81860382612a3d565b60405191829160208352602083019061286b565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610b6657509091508101602001610b0f82610aff565b919260018160209254838588010152019101909291610b4d565b60ff191660208087019190915292151560051b85019092019250610b0f9150839050610aff565b602483634e487b7160e01b81526022600452fd5b92607f1692610ae2565b50346102a157806003193601126102a15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610c8a906135fb565b9060058210159081610ccb5760028314918215610cdf575b8215610cb6575b6020836040519015158152f35b909150610ccb57506004602091145f80610ca9565b80634e487b7160e01b602492526021600452fd5b5060038314915080610ca2565b50346102a15760203660031901126102a15760043590604051610180810181811067ffffffffffffffff82111761100d576060916101609160405283815283602082015283604082015283838201528360808201528360a08201528360c08201528360e08201528361010082015283610120820152610d69612e91565b6101408201520152818152600960205260ff600160408320015460a81c161561031657815f52600960205260405f2060405190610da582612a20565b8054916001600160a01b0383168152602081019364ffffffffff8460a01c168552604082019264ffffffffff8560c81c168452606083019360ff8660f01c1615158552608084019560f81c1515865260018201549260a08501956001600160a01b038516875260c086019060ff8660a01c1615158252610e46600260e089019660ff8960a81c161515885260ff6101008b019960b01c161515895201612eaf565b61012088019081526002610e598d6135fb565b610e62816129ad565b14611005575b5197516001600160a01b0316935164ffffffffff1690511515915115159451151595511515968b5f52600360205260405f20546001600160a01b03169b8452600a6020526040842090516001600160a01b03169a5164ffffffffff169951151593506040519a610eda6101808d612a3d565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610f2e90612ee1565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105739161293b565b838252610e68565b602483634e487b7160e01b81526041600452fd5b50346102a15760203660031901126102a15760043567ffffffffffffffff811161088a5761105390369060040161290a565b9061105c6137db565b82915b80831061106a578380f35b611075838284612e20565b359261107f6137db565b835f52600960205260ff600160405f20015460a81c16156113ac578385526009602052604085206001015460a01c60ff16156110c85760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c61139a576110fd815f5260096020526001600160a01b0360405f205416331490565b156113845761110b8161356c565b90805f526009602052611123600260405f2001612eaf565b916001600160801b038351166001600160801b038216101561137157815f52600960205260ff60405f205460f01c161561135e579061117a826001600160801b036020818796818d99511603169501511690612ab1565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215611339575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506112966001600160a01b03600160405f200154169461126e8b8588614510565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6112da575b505050505050600101919061105f565b813b1561133557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161131d575b808080806112ca565b9061132791612a3d565b835f126105f657835f611314565b8580fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556111c4565b506339c6dc7360e21b8652600452602485fd5b506322cad1af60e11b8652600452602485fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b838562b8e7e760e51b8152602491600452fd5b50346102a15760203660031901126102a157600435906113dd6137db565b818152600960205260ff600160408320015460a81c161561031657611401826135fb565b61140a816129ad565b600481036114255750602491634a5541ef60e01b8252600452fd5b61142e816129ad565b60038103611449575060249163fe19f19f60e01b8252600452fd5b600290611455816129ad565b146115ad57611478825f5260096020526001600160a01b0360405f205416331490565b1561158e57818152600960205260ff604082205460f01c161561157c57818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a1805f5260036020526001600160a01b0360405f20541690813b61151e575050f35b813b156115785782916024839260405195869384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611565579050f35b61156e91612a3d565b805f126102a15780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b82526004526001600160a01b033316602452fd5b6024916322cad1af60e11b8252600452fd5b50346102a15760203660031901126102a1576004356001600160a01b03811680910361088a576001600160a01b0382541633810361169c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116885760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346102a15760203660031901126102a1576116e5612890565b9080546001600160a01b03811633810361169c57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346102a15760203660031901126102a1576001600160a01b0361175f612890565b16801561177c578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346102a15760203660031901126102a15760206117c7600435613539565b6001600160a01b0360405191168152f35b50346102a15760203660031901126102a157600435906117f6612e79565b50818152600960205260ff600160408320015460a81c1615610316579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c1682519161184883612a04565b8252602082015261186e8251809264ffffffffff60208092828151168552015116910152565bf35b50346102a15760203660031901126102a1576004359067ffffffffffffffff82116102a15781360361012060031982011261088a576118ad6137db565b60c4830135906022190181121561088a57820160048101359067ffffffffffffffff821161029d5760240190606081023603821361029d57906118f1913691612d54565b8051916118fd83612d3c565b9261190b6040519485612a3d565b808452601f1961191a82612d3c565b01825b818110611b0f57505064ffffffffff4216926001600160801b0361194082613835565b51511667ffffffffffffffff602061195784613835565b5101511664ffffffffff80604061196d86613835565b510151168701169060405192611982846129e8565b83526020830152604082015261199786613835565b526119a185613835565b5060015b828110611a7b575050506119bb84600401612e58565b906119c860248601612e58565b906119d560448701612e44565b6064870135916001600160a01b0383168093036102a1576020611a73611a33611a688b8b8b8b8b8b6001600160801b038c6001600160a01b03611a1a60848a01612e6c565b9481611a2860a48c01612e6c565b976040519d8e6129b7565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612df1565b610100820152613856565b604051908152f35b806001600160801b03611a9060019385613842565b51511667ffffffffffffffff6020611aa88487613842565b5101511664ffffffffff806040611ac25f1987018d613842565b51015116816040611ad3878a613842565b5101511601169060405192611ae7846129e8565b835260208301526040820152611afd8289613842565b52611b088188613842565b50016119a5565b602090611b1a612e91565b8282890101520161191d565b50346102a15760403660031901126102a15760043567ffffffffffffffff811161088a57611b5890369060040161290a565b9060243567ffffffffffffffff81116105f657611b7990369060040161290a565b611b816137db565b808403611bef57845b848110611b95578580f35b80611be9611ba66001938888612e20565b35611bb2838989612e20565b35895260036020526001600160a01b0360408a205416611bdb611bd685888a612e20565b612e44565b91611be46137db565b6134a9565b01611b8a565b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883614006565b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c16156103165780611c96836135fb565b926005841015611cd157600260209403611cb7575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80611cab565b602482634e487b7160e01b81526021600452fd5b50346102a157806003193601126102a15760206001600160a01b0360085416604051908152f35b50346102a15760203660031901126102a157600435611d296137db565b808252600960205260ff600160408420015460a81c161561099e57808252600960205260ff600160408420015460a01c1615611ebe57611d6881613f94565b15611ea85780825260036020526001600160a01b03604083205416151580611ea1575b80611e84575b611e72577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b036040832054168015908115611e3b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611e29575080f35b637e27328960e01b8252600452602490fd5b611e5a835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f19019055611ddf565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c1615611d91565b5081611d8b565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346102a15761029a611efb366128d0565b9060405192611f0b602085612a3d565b858452612f68565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460a01c166040519015158152f35b50346121fa5760203660031901126121fa5760043590611f836137db565b815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c165f14611fcd5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c61226857612000815f5260096020526001600160a01b0360405f205416331490565b156122495761200e8161356c565b90805f526009602052612026600260405f2001612eaf565b916001600160801b038351166001600160801b038216101561223657815f52600960205260ff60405f205460f01c161561222357806001600160801b0360208161207a948188511603169501511690612ab1565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b038116919082156121fe575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061216e6001600160a01b03600160405f200154169461126e8b8588614510565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6121a5578580f35b813b156121fa575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e7575b808080808580f35b6121f391505f90612a3d565b5f806121df565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556120c4565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa5760043567ffffffffffffffff81116121fa5761014060031982360301126121fa576122c66137db565b604051906122d3826129b7565b6122df816004016128bc565b82526122ed602482016128bc565b60208301526122fe60448201612a7b565b604083015260648101356001600160a01b03811681036121fa576060830152612329608482016129a0565b608083015261233a60a482016129a0565b60a083015261234b60c48201612d2a565b60c083015260e481013567ffffffffffffffff81116121fa57810191366023840112156121fa57611a68611a739261238f6020953690602460048201359101612d54565b60e0840152610104369101612df1565b346121fa576123b66123b0366128d0565b91612ae5565b005b346121fa575f3660031901126121fa576020600754604051908152f35b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d5761240d906135fb565b600581101561243957806020911590811561242e575b506040519015158152f35b600191501482612423565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d576020905f90805f526009835260ff60405f205460f01c16806124f3575b6124c1575b506001600160801b0360405191168152f35b6124ed9150805f52600983526124e76001600160801b03600260405f200154169161356c565b90612ab1565b826124af565b50805f526009835260ff600160405f20015460a01c16156124aa565b346121fa5760403660031901126121fa57612528612890565b60243561253481613539565b33151580612601575b806125ce575b6125a25781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612543565b50336001600160a01b038216141561253d565b346121fa5760203660031901126121fa5760206117c7600435612a8f565b346121fa575f3660031901126121fa576040515f6001548060011c9060018116801561271c575b602083108114612708578285529081156126e45750600114612686575b61057383610b0f81850382612a3d565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106126ca57509091508101602001610b0f612676565b9192600181602092548385880101520191019092916126b2565b60ff191660208086019190915291151560051b84019091019150610b0f9050612676565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612659565b346121fa575f3660031901126121fa57602060405167016345785d8a00008152f35b346121fa5760203660031901126121fa57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036121fa57817f4906490600000000000000000000000000000000000000000000000000000000602093149081156127bc575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612820575b81156127f6575b50836127b5565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836127ef565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506127e8565b5f5b83811061285b5750505f910152565b818101518382015260200161284c565b906020916128848151809281855285808601910161284a565b601f01601f1916010190565b600435906001600160a01b03821682036121fa57565b602435906001600160a01b03821682036121fa57565b35906001600160a01b03821682036121fa57565b60609060031901126121fa576004356001600160a01b03811681036121fa57906024356001600160a01b03811681036121fa579060443590565b9181601f840112156121fa5782359167ffffffffffffffff83116121fa576020808501948460051b0101116121fa57565b90602080835192838152019201905f5b8181106129585750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161294b565b359081151582036121fa57565b6005111561243957565b610120810190811067ffffffffffffffff8211176129d457604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176129d457604052565b6040810190811067ffffffffffffffff8211176129d457604052565b610140810190811067ffffffffffffffff8211176129d457604052565b90601f8019910116810190811067ffffffffffffffff8211176129d457604052565b67ffffffffffffffff81116129d457601f01601f191660200190565b35906001600160801b03821682036121fa57565b612a9881613539565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b038211612ad157565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b03168015612d1757815f5260036020526001600160a01b0360405f205416151580612d0f575b80612cf2575b612cdf577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2a575b6001600160a01b03935085612bf3575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612bdb57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c12825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b7a565b9192905080612c88575b15612c4157828291612b6a565b8284612c5957637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cb6575b80612c345750825f526005602052336001600160a01b0360405f20541614612c34565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c93565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615612b1a565b506001612b14565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff821682036121fa57565b67ffffffffffffffff81116129d45760051b60200190565b929192612d6082612d3c565b93612d6e6040519586612a3d565b60606020868581520193028201918183116121fa57925b828410612d925750505050565b6060848303126121fa5760405190612da9826129e8565b612db285612a7b565b825260208501359067ffffffffffffffff821682036121fa5782602092836060950152612de160408801612d2a565b6040820152815201930192612d85565b91908260409103126121fa57604051612e0981612a04565b6020808294612e17816128bc565b84520135910152565b9190811015612e305760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036121fa5790565b356001600160a01b03811681036121fa5790565b3580151581036121fa5790565b60405190612e8682612a04565b5f6020838281520152565b60405190612e9e826129e8565b5f6040838281528260208201520152565b90604051612ebc816129e8565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612eed81612d3c565b92612efb6040519485612a3d565b81845260208401905f5260205f205f915b838310612f195750505050565b600160208192604051612f2b816129e8565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f0c565b90612f74838284612ae5565b803b612f81575b50505050565b602091612fc76001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061286b565b03815f865af15f918161304f575b506130035750612fe3614087565b80519081612ffe5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361303d57505f808080612f7b565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116130a4575b8161306b60209383612a3d565b810103126121fa57517fffffffff00000000000000000000000000000000000000000000000000000000811681036121fa57905f612fd5565b3d915061305e565b9190916130b76137db565b805f52600960205260ff600160405f20015460a81c161561244d575f92815f52600960205260ff600160405f20015460a01c16613496576001600160a01b03811691821561346b576001600160801b038416801561343f57815f5260036020526001600160a01b0360405f20541690818514158061342f575b6133fb576001600160801b03613145846140b6565b168082116133c85750825f5260096020526001600160a01b0360405f20541694835f52600960205261318187600260405f20015460801c6140dc565b5f85815260096020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556131c490612eaf565b6001600160801b036131e88160208401511692826040818351169201511690612ab1565b161115613396575b835f526009602052837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160405f2001541694613239818a88614510565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1803314158061338c575b613324575b833314159081613319575b8161330e575b50613297575b5050505050565b823b1561330a57604051636fd110e960e01b815260048101919091523360248201526001600160a01b0390911660448201526001600160801b039092166064830152829082908183816084810103925af16132f5575b808080613290565b613300828092612a3d565b6102a157806132ed565b8480fd5b90508314155f61328a565b843b15159150613284565b803b156121fa57604051636fd110e960e01b8152600481018390523360248201526001600160a01b03841660448201526001600160801b03861660648201525f8160848183865af1613377575b50613279565b6133849196505f90612a3d565b5f945f613371565b50803b1515613274565b5f84815260096020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131f0565b90837fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b84837fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061343983613f94565b15613130565b507fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b9190915f92815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c16613496576001600160a01b03811691821561346b576001600160801b038416801561343f57815f5260036020526001600160a01b0360405f20541690818514158061342f576133fb576001600160801b03613145846140b6565b805f5260036020526001600160a01b0360405f20541690811561355a575090565b637e27328960e01b5f5260045260245ffd5b64ffffffffff4216815f5260096020528064ffffffffff60405f205460a01c1610156135f557815f52600960205264ffffffffff60405f205460c81c1611156135da57805f52600a602052600160405f2054115f146135d1576135ce906141bc565b90565b6135ce906140fc565b5f5260096020526001600160801b03600260405f2001541690565b50505f90565b805f52600960205260ff600160405f20015460a01c165f1461361d5750600490565b805f52600960205260405f205460f81c61368957805f52600960205264ffffffffff60405f205460a01c164210613684576136578161356c565b905f5260096020526001600160801b0380600260405f200154169116105f1461367f57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f2054161515806137c9575b806137ac575b61379a577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613763575b168061374b575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613707565b613782835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613700565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c16156136b4565b506001600160a01b03821615156136ae565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361380d57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e305760200190565b8051821015612e305760209160051b010190565b906138786001600160801b0360408401511660206101008501510151906143d2565b916001600160801b038351169060e08101519160c082019264ffffffffff8451168215613f6c578015613f445781518015613f1c577f00000000000000000000000000000000000000000000000000000000000000008111613ef1575064ffffffffff60406138e684613835565b51015116811015613ead57505f905f905f81515f905b808210613e25575050505064ffffffffff80421691169081811015613df75750506001600160801b031690818103613dc957505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613ad18751975f19890190613842565b51015160c81b169360a01b169116171785555f5b818110613cbb575050600187016007556001600160a01b036020830151168015612d1757613b1b886001600160a01b039261368f565b16613c8f578682613b696001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906144af565b6001600160801b0360208401511680613c5f575b506001600160a01b0381511694613c54613c366001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613bdb8b612a04565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061293b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613c89906001600160a01b036060840151166001600160a01b0361010085015151169033906144af565b5f613b7d565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f2090613cd68160e0870151613842565b518254680100000000000000008110156129d45760018101808555811015612e30576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613ae5565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613e49906001600160801b03613e408588613842565b515116906140dc565b9364ffffffffff806040613e5d8685613842565b51015116941680851115613e79575060018493019092916138fc565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613ebe84613835565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613fda575b508115613fc1575090565b90506001600160a01b03613fd53392612a8f565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613fb6565b805f52600960205261401d600260405f2001612eaf565b90805f52600960205260ff600160405f20015460a01c165f1461404b5750602001516001600160801b031690565b90815f52600960205260405f205460f81c61406a57506135ce9061356c565b6135ce91506001600160801b036040818351169201511690612ab1565b3d156140b1573d9061409882612a5f565b916140a66040519384612a3d565b82523d5f602084013e565b606090565b6135ce906140c381614006565b905f526009602052600260405f20015460801c90612ab1565b906001600160801b03809116911601906001600160801b038211612ad157565b5f818152600960205260409020546141339064ffffffffff60a082901c811660c89290921c81168290038116914282160316614560565b90805f52600a60205260405f20805415612e30575f5261418867ffffffffffffffff60205f205460801c1692825f5260096020526141836001600160801b03600260405f20015416948592614640565b6146b3565b9182136141a557506141a16001600160801b039161478e565b1690565b90505f526009602052600260405f20015460801c90565b9064ffffffffff421691805f52600960205260405f2090604051906141e082612a20565b61012061427360028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eaf565b92019182525f52600a60205261428b60405f20612ee1565b915f9264ffffffffff604061429f83613835565b510151168664ffffffffff5f925b1610614393578161432464ffffffffff9697988784816001600160801b036142dc614183986143299b9a613842565b5151169a8b9867ffffffffffffffff60206142f7868b613842565b51015116978260406143098784613842565b510151169480614376575050511680925b0316920316614560565b614640565b91821361434a5750906001600160801b03614344819361478e565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f14614371575090565b905090565b6040925090614388915f190190613842565b51015116809261431a565b936001600160801b03600191816143aa8886613842565b51511601169401958064ffffffffff8060406143c68b87613842565b510151169892986142ad565b9190916040516143e181612a04565b5f81525f6020820152926001600160801b0382169081156144925767016345785d8a0000811161445b5761441d6001600160801b0391836153b4565b1660208501918183521115614447576001600160801b03918261444292511690612ab1565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144a381612a04565b5f81525f602082015290565b9091926001600160a01b0361450e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614509608483612a3d565b6147c3565b565b61450e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614509606483612a3d565b600160ff1b81148015614633575b61460b575f81121561460257614592815f035b5f8412156145fb57835f0390614851565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116145cc575f19911813156145c75790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614851565b61459281614581565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461456e565b8061465a575061465657670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146146a5578061467d575050670de0b6b3a764000090565b670de0b6b3a764000081146146a15761469c906141836135ce93614957565b614aae565b5090565b5050670de0b6b3a764000090565b600160ff1b81148015614781575b614759575f811215614750576146e5815f035b5f84121561474957835f03906153b4565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471a575f19911813156145c75790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906153b4565b6146e5816146d4565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b5f81126147985790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b036147ec93169360208151910182865af16147e5614087565b9083615462565b805190811515918261482d575b50506148025750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126121fa57602001518015908115036121fa575f806147f9565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461491c57818410156148e257670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614929570490565b634e487b7160e01b5f52601260045260245ffd5b8015614929576ec097ce7bc90715b34b9f10000000000590565b805f811315614a8357670de0b6b3a76400008112614a6357506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614a5057506706f05b59d3b20000905b5f8213614a1a5750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614a42575b60011d90614a0d565b809192019160011d90614a39565b9050670de0b6b3a7640000929150020290565b5f1991508015614929576ec097ce7bc90715b34b9f100000000005614974565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614adb5768033dd1780914b9711419811261368457614ad2905f03614aae565b6135ce9061493d565b680a688906bd8affffff811361538957670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff000000000000008216615254575b670de0b6b3a76400009066ff0000000000008316615144575b65ff0000000000831661503c575b64ff000000008316614f3c575b63ff0000008316614e44575b62ff00008316614d54575b61ff008316614c6c575b60ff8316614b8c575b029060401c60bf031c90565b60808316614c59575b60408316614c46575b60208316614c33575b60108316614c20575b60088316614c0d575b60048316614bfa575b60028316614be7575b6001831615614b8057680100000000000000010260401c614b80565b680100000000000000010260401c614bcb565b680100000000000000030260401c614bc2565b680100000000000000060260401c614bb9565b6801000000000000000b0260401c614bb0565b680100000000000000160260401c614ba7565b6801000000000000002c0260401c614b9e565b680100000000000000590260401c614b95565b6180008316614d41575b6140008316614d2e575b6120008316614d1b575b6110008316614d08575b6108008316614cf5575b6104008316614ce2575b6102008316614ccf575b610100831615614b7757680100000000000000b10260401c614b77565b680100000000000001630260401c614cb2565b680100000000000002c60260401c614ca8565b6801000000000000058c0260401c614c9e565b68010000000000000b170260401c614c94565b6801000000000000162e0260401c614c8a565b68010000000000002c5d0260401c614c80565b680100000000000058b90260401c614c76565b628000008316614e31575b624000008316614e1e575b622000008316614e0b575b621000008316614df8575b620800008316614de5575b620400008316614dd2575b620200008316614dbf575b62010000831615614b6d576801000000000000b1720260401c614b6d565b680100000000000162e40260401c614da1565b6801000000000002c5c80260401c614d96565b68010000000000058b910260401c614d8b565b680100000000000b17210260401c614d80565b68010000000000162e430260401c614d75565b680100000000002c5c860260401c614d6a565b6801000000000058b90c0260401c614d5f565b63800000008316614f29575b63400000008316614f16575b63200000008316614f03575b63100000008316614ef0575b63080000008316614edd575b63040000008316614eca575b63020000008316614eb7575b6301000000831615614b625768010000000000b172180260401c614b62565b6801000000000162e4300260401c614e98565b68010000000002c5c8600260401c614e8c565b680100000000058b90c00260401c614e80565b6801000000000b17217f0260401c614e74565b680100000000162e42ff0260401c614e68565b6801000000002c5c85fe0260401c614e5c565b68010000000058b90bfc0260401c614e50565b6480000000008316615029575b6440000000008316615016575b6420000000008316615003575b6410000000008316614ff0575b6408000000008316614fdd575b6404000000008316614fca575b6402000000008316614fb7575b640100000000831615614b5657680100000000b17217f80260401c614b56565b68010000000162e42ff10260401c614f97565b680100000002c5c85fe30260401c614f8a565b6801000000058b90bfce0260401c614f7d565b68010000000b17217fbb0260401c614f70565b6801000000162e42fff00260401c614f63565b68010000002c5c8601cc0260401c614f56565b680100000058b90c0b490260401c614f49565b658000000000008316615131575b65400000000000831661511e575b65200000000000831661510b575b6510000000000083166150f8575b6508000000000083166150e5575b6504000000000083166150d2575b6502000000000083166150bf575b65010000000000831615614b49576801000000b1721835510260401c614b49565b680100000162e430e5a20260401c61509e565b6801000002c5c863b73f0260401c615090565b68010000058b90cf1e6e0260401c615082565b680100000b1721bcfc9a0260401c615074565b68010000162e43f4f8310260401c615066565b680100002c5c89d5ec6d0260401c615058565b6801000058b91b5bc9ae0260401c61504a565b66800000000000008316615241575b6640000000000000831661522e575b6620000000000000831661521b575b66100000000000008316615208575b660800000000000083166151f5575b660400000000000083166151e2575b660200000000000083166151cf575b6601000000000000831615614b3b5768010000b17255775c040260401c614b3b565b6801000162e525ee05470260401c6151ad565b68010002c5cc37da94920260401c61519e565b680100058ba01fb9f96d0260401c61518f565b6801000b175effdc76ba0260401c615180565b680100162f3904051fa10260401c615171565b6801002c605e2e8cec500260401c615162565b68010058c86da1c09ea20260401c615153565b678000000000000000821661536a575b670de0b6b3a7640000906740000000000000008316615357575b6720000000000000008316615344575b6710000000000000008316615331575b670800000000000000831661531e575b670400000000000000831661530b575b67020000000000000083166152f8575b67010000000000000083166152e5575b9050614b22565b680100b1afa5abcbed610260401c6152de565b68010163da9fb33356d80260401c6152ce565b680102c9a3e778060ee70260401c6152be565b6801059b0d31585743ae0260401c6152ae565b68010b5586cf9890f62a0260401c61529e565b6801172b83c7d517adce0260401c61528e565b6801306fe0a31b7152df0260401c61527e565b5077b504f333f9de648480000000000000000000000000000000615264565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461545157670de0b6b3a7640000821015615421577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061549f575080511561547757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806154e5575b6154b0575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156154a856fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614b456040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561475c90816103e9823960805181613aa70152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461309f57508063027b67441461307d57806306fdde0314612f89578063081812fc14612f6b578063095ea7b314612e665780631400ecec14612db55780631c1cdd4c14612d2c5780631e99d56914612d0f57806323b872dd14612cf657806340e58ee5146129e1578063425d30dd1461298f57806342842e0e1461296557806342966c681461278857806344267570146127615780634857501f146126eb5780634869e12d146126af5780634cc55e11146121f657806353b15727146120c857806357404b121461200d5780636352211e14611fdd5780636d0cee7514611fdd57806370a0823114611f7257806375829def14611f00578063780a82c814611eb25780637cad6cd114611da65780637de6b1db14611bb15780638659c2701461180d578063894e9a0d1461150b5780638f69b993146114705780639067b6771461141f57806395d89b4114611312578063a22cb4651461125c578063a80fc07114611209578063ab167ccc1461108c578063ad35efd414611019578063b256456914610fc7578063b88d4fde14610f36578063b8a3be6614610f01578063b971302a14610eb1578063bc2be1be14610e60578063c156a11d146109a8578063c87b56dd14610888578063d4dbd20b14610835578063d511609f146107e8578063d975dfed1461079b578063e985e9c514610748578063ea5ead1914610721578063eac8f5b8146106ce578063f590c17614610671578063f851a4401461064b5763fdd46d601461024f575f80fd5b346104d65760603660031901126104d6576004359061026c6131ca565b61027461332c565b9261027d613a9d565b808352600960205260ff600160408520015460a81c161561063a57808352600960205260ff600160408520015460a01c16610628576001600160a01b038216938415610615576001600160801b03811680156106025782855260036020526001600160a01b0360408620541680871415806105f2575b6105d7576001600160801b03610308856142e7565b168083116105bc575083865260096020526001600160a01b0360408720541691848752600960205280600260408920015460801c01976001600160801b0389116105a8576103808899878a526009602052600260408b2001906001600160801b036001600160801b031983549260801b169116179055565b8588526009602052610397600260408a200161361f565b6001600160801b036103bb8160208401511692826040818351169201511690613364565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c8861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916132ee565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916132ee565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b602488634e487b7160e01b81526011600452fd5b86606491848763287ecaef60e21b8452600452602452604452fd5b606486888663b34359d360e01b835260045233602452604452fd5b506105fc84613af7565b156102f3565b6024858463d2aabcd960e01b8252600452fd5b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576004359061073f6131ca565b610274836142e7565b50346104d65760403660031901126104d6576001600160a01b03604061076c6131b4565b92826107766131ca565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d7836142e7565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d6576004356108a6816137a9565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa90811561099d578291610916575b604051602080825281906109129082018561318f565b0390f35b90503d8083833e61092781836132ee565b8101906020818303126109955780519067ffffffffffffffff8211610999570181601f820112156109955780519261095e84613310565b9261096c60405194856132ee565b848452602085840101116104d657506109129261098f916020808501910161316e565b5f6108fc565b8280fd5b8380fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d657600435906109c66131ca565b916109cf613a9d565b808252600960205260ff600160408420015460a81c1615610e4e5780825260036020526001600160a01b0360408320541692833303610e3757610a11826142e7565b6001600160801b0381169081158015610a99575b5050506001600160a01b03811615610a8657610a49826001600160a01b0392613951565b1680610a625760248383637e27328960e01b8252600452fd5b90838203610a6e578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610aa1613a9d565b848652600960205260ff600160408820015460a81c1615610e2557848652600960205260ff600160408820015460a01c16610e12578615610dff57610dec5783855260036020526001600160a01b036040862054168087141580610ddc575b610dc1576001600160801b03610b15866142e7565b16808411610da6575084865260096020526001600160a01b0360408720541692858752600960205280600260408920015460801c016001600160801b0381116105a857610b8b908789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b8587526009602052610ba26002604089200161361f565b6001600160801b03610bc68160208401511692826040818351169201511690613364565b161115610d6a575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610c1881868861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610d60575b610cf5575b823314159081610cea575b81610cdf575b50610c75575b80610a25565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610c6f5781610cd4916132ee565b61099557825f610c6f565b90508214155f610c69565b833b15159150610c63565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610d4b575b5050610c58565b81610d55916132ee565b61055e57855f610d44565b50803b1515610c53565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610bce565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610de685613af7565b15610b00565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610f506131b4565b610f586131ca565b906064359067ffffffffffffffff821161099957366023830112156109995781600401359284610f8785613310565b93610f9560405195866132ee565b8585523660248783010111610fc35785610fc096602460209301838801378501015260443591613665565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b57611052906138bd565b60405190600581101561106757602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d6576101403660031901126104d6576110a7613a9d565b6110af613601565b9064ffffffffff421680835264ffffffffff6110c9613651565b166111ee575b60e4359064ffffffffff82168203610995570164ffffffffff1660408301526001600160a01b03600435908116929083810361099557506024356001600160a01b0381169081810361099957506044356001600160801b038116908181036104d957506064356001600160a01b0381168091036104d95760843591821515928381036111ea575060a43593841515948581036111e65750604051976111738961324b565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126104d657604051906111ad826132d2565b61010435906001600160a01b03821682036104d65760206111de8585858152610124358482015260e0820152613bed565b604051908152f35b8780fd5b8680fd5b64ffffffffff6111fc613651565b82011660208401526110cf565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576112766131b4565b60243590811515809203610995576001600160a01b03169081156112e657338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611415575b602084108114611401578386529081156113da575060011461137d575b61091284611369818603826132ee565b60405191829160208352602083019061318f565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106113c05750909150810160200161136982611359565b9192600181602092548385880101520191019092916113a7565b60ff191660208087019190915292151560051b850190920192506113699150839050611359565b602483634e487b7160e01b81526022600452fd5b92607f169261133c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b576114a9906138bd565b90600582101590816114ea57600283149182156114fe575b82156114d5575b6020836040519015158152f35b9091506114ea57506004602091145f806114c8565b80634e487b7160e01b602492526021600452fd5b50600383149150806114c1565b50346104d65760203660031901126104d657600435908061016060405161153181613298565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611574613601565b6101408201520152818152600960205260ff600160408320015460a81c16156106bd5781815260096020526040812091604051906115b1826132b5565b8354906001600160a01b0382168352602083019464ffffffffff8360a01c168652604084019464ffffffffff8460c81c168652606085019060ff8560f01c1615158252608086019460f81c1515855260018301549560a08101966001600160a01b038116885260c082019660ff8260a01c1615158852611652600260e085019760ff8560a81c161515895260ff61010087019560b01c16151585520161361f565b6101208401908152611663886138bd565b60058110156117f9576002146117f1575b5198516001600160a01b031693878152600a602052604081205464ffffffffff169a5164ffffffffff1695511515925115159851151596511515978152600360205260409020546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516116e981613298565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b848652611674565b602486634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff8111610fc35761183f90369060040161321a565b90611848613a9d565b82915b808310611856578380f35b6118618382846135dd565b359261186b613a9d565b838552600960205260ff600160408720015460a81c1615611b9f578385526009602052604085206001015460a01c60ff16156118b45760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611b8d576118e9815f5260096020526001600160a01b0360405f205416331490565b15611b77576118f7816137dc565b90808652600960205261190f6002604088200161361f565b916001600160801b038351166001600160801b0382161015611b6457818752600960205260ff604088205460f01c1615611b515790611966826001600160801b036020818796818d99511603169501511690613364565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611b2c575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a906001600160a01b03600160408d2001541694611a688b858861430d565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611ad4575b505050505050600101919061184b565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b17575b80808080611ac4565b81611b21916132ee565b61099957835f611b0e565b818552600960205260016040862001600160a01b60ff60a01b198254161790556119c7565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590611bcf613a9d565b818152600960205260ff600160408320015460a81c16156106bd57611bf3826138bd565b6005811015611d925760048103611c175750602491634a5541ef60e01b8252600452fd5b60038103611c32575060249163fe19f19f60e01b8252600452fd5b600214611d8057611c57825f5260096020526001600160a01b0360405f205416331490565b15611d6a57818152600960205260ff604082205460f01c1615611d5857818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611cfd575050f35b813b15611d545782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611d435750f35b81611d4d916132ee565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b038116809103610fc3576001600160a01b03825416338103611e83575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e6f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff9352600a8452205416604051908152f35b50346104d65760203660031901126104d657611f1a6131b4565b9080546001600160a01b038116338103611e8357506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b03611f946131b4565b168015611fb1578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020611ffc6004356137a9565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d6576004359061202b613601565b50818152600960205260ff600160408320015460a81c16156106bd57816060928252600960205264ffffffffff6040818185205460a01c1693838152600a6020528282822054169381526009602052205460c81c16906040519261208e8461327c565b8352602083015260408201526120c6604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b50346104d6576101603660031901126104d6576120e3613a9d565b604051906120f08261324b565b6120f86131b4565b82526121026131ca565b602083015261210f61332c565b60408301526064356001600160a01b0381168103610fc35760608301526084358015158103610fc357608083015260a4358015158103610fc35760a083015260603660c31901126104d6576040516121668161327c565b60c43564ffffffffff8116810361099557815260e43564ffffffffff811681036109955760208201526101043564ffffffffff8116810361099557604082015260c08301526040610123193601126104d657604051906121c5826132d2565b61012435906001600160a01b03821682036104d65760206111de8585858152610144358482015260e0820152613bed565b50346104d65760403660031901126104d65760043567ffffffffffffffff8111610fc35761222890369060040161321a565b9060243567ffffffffffffffff81116109995761224990369060040161321a565b612251613a9d565b80840361267f57845b848110612265578580f35b6122708186866135dd565b3561227c8287876135dd565b35875260036020526001600160a01b036040882054169061229e8385876135dd565b356001600160801b03811680820361267b576122b8613a9d565b828a52600960205260ff600160408c20015460a81c161561266957828a52600960205260ff600160408c20015460a01c1661265657831561264357801561263057828a5260036020526001600160a01b0360408b205416908185141580612620575b612605576001600160801b0361232f856142e7565b168082116125ea5750908a91848352600960205280600260406001600160a01b03818720541695888152600960205220015460801c016001600160801b0381116125d657906123ad86959493928e989789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b84875260096020526123c46002604089200161361f565b6001600160801b036123e88160208401511692826040818351169201511690613364565b16111561259a575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461243a81868861430d565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580612590575b612525575b81331415908161251a575b8161250f575b5061249e575b505050505060010161225a565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16124fa575b808080612491565b81612504916132ee565b61055e57855f6124f2565b90508114155f61248b565b823b15159150612485565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af161257b575b505061247a565b81612585916132ee565b61055e57855f612574565b50803b1515612475565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556123f0565b60248d634e487b7160e01b81526011600452fd5b8b906064928663287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061262a84613af7565b1561231a565b60248a8463d2aabcd960e01b8252600452fd5b60248a84630ff7ee2d60e31b8252600452fd5b60248a84634a5541ef60e01b8252600452fd5b60248a8462b8e7e760e51b8252600452fd5b8980fd5b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d783613b69565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5780612726836138bd565b926005841015611d9257600260209403612747575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061273b565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d6576004356127a5613a9d565b808252600960205260ff600160408420015460a81c161561107b57808252600960205260ff600160408420015460a01c161561293a576127e481613af7565b156129245780825260036020526001600160a01b0360408320541615158061291d575b80612900575b6128ee577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b0360408320541680159081156128b7575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506128a5575080f35b637e27328960e01b8252600452602490fd5b6128d6835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561285b565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c161561280d565b5081612807565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d657610fc0612977366131e0565b90604051926129876020856132ee565b858452613665565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612c6d576020366003190112612c6d57600435906129ff613a9d565b815f52600960205260ff600160405f20015460a81c1615612ce457815f52600960205260ff600160405f20015460a01c165f14612a495750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612cd257612a7c815f5260096020526001600160a01b0360405f205416331490565b15612cbc57612a8a816137dc565b90805f526009602052612aa2600260405f200161361f565b916001600160801b038351166001600160801b0382161015612ca957815f52600960205260ff60405f205460f01c1615612c9657806001600160801b03602081612af6948188511603169501511690613364565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612c71575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612be16001600160a01b03600160405f2001541694611a688b858861430d565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612c18578580f35b813b15612c6d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c5a575b808080808580f35b612c6691505f906132ee565b5f80612c52565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612b40565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612c6d57612d0d612d07366131e0565b91613398565b005b34612c6d575f366003190112612c6d576020600754604051908152f35b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da457612d64906138bd565b6005811015612d90578060209115908115612d85575b506040519015158152f35b600191501482612d7a565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da4576020905f90805f526009835260ff60405f205460f01c1680612e4a575b612e18575b506001600160801b0360405191168152f35b612e449150805f5260098352612e3e6001600160801b03600260405f20015416916137dc565b90613364565b82612e06565b50805f526009835260ff600160405f20015460a01c1615612e01565b34612c6d576040366003190112612c6d57612e7f6131b4565b602435612e8b816137a9565b33151580612f58575b80612f25575b612ef95781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612e9a565b50336001600160a01b0382161415612e94565b34612c6d576020366003190112612c6d576020611ffc600435613342565b34612c6d575f366003190112612c6d576040515f6001548060011c90600181168015613073575b60208310811461305f5782855290811561303b5750600114612fdd575b61091283611369818503826132ee565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061302157509091508101602001611369612fcd565b919260018160209254838588010152019101909291613009565b60ff191660208086019190915291151560051b840190910191506113699050612fcd565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612fb0565b34612c6d575f366003190112612c6d57602060405167016345785d8a00008152f35b34612c6d576020366003190112612c6d57600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612c6d57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115613144575b811561311a575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613113565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061310c565b5f5b83811061317f5750505f910152565b8181015183820152602001613170565b906020916131a88151809281855285808601910161316e565b601f01601f1916010190565b600435906001600160a01b0382168203612c6d57565b602435906001600160a01b0382168203612c6d57565b6060906003190112612c6d576004356001600160a01b0381168103612c6d57906024356001600160a01b0381168103612c6d579060443590565b9181601f84011215612c6d5782359167ffffffffffffffff8311612c6d576020808501948460051b010111612c6d57565b610100810190811067ffffffffffffffff82111761326857604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761326857604052565b610180810190811067ffffffffffffffff82111761326857604052565b610140810190811067ffffffffffffffff82111761326857604052565b6040810190811067ffffffffffffffff82111761326857604052565b90601f8019910116810190811067ffffffffffffffff82111761326857604052565b67ffffffffffffffff811161326857601f01601f191660200190565b604435906001600160801b0382168203612c6d57565b61334b816137a9565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161338457565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156135ca57815f5260036020526001600160a01b0360405f2054161515806135c2575b806135a5575b613592577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134dd575b6001600160a01b039350856134a6575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361348e57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6134c5825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561342d565b919290508061353b575b156134f45782829161341d565b828461350c57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613569575b806134e75750825f526005602052336001600160a01b0360405f205416146134e7565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613546565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c16156133cd565b5060016133c7565b633250574960e11b5f525f60045260245ffd5b91908110156135ed5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061360e8261327c565b5f6040838281528260208201520152565b9060405161362c8161327c565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff81168103612c6d5790565b90613671838284613398565b803b61367e575b50505050565b6020916136c46001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061318f565b03815f865af15f918161374c575b5061370057506136e06142b8565b805190816136fb5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361373a57505f808080613678565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116137a1575b81613768602093836132ee565b81010312612c6d57517fffffffff0000000000000000000000000000000000000000000000000000000081168103612c6d57905f6136d2565b3d915061375b565b805f5260036020526001600160a01b0360405f2054169081156137ca575090565b637e27328960e01b5f5260045260245ffd5b805f52600a60205264ffffffffff60405f205416815f52600960205264ffffffffff60405f205460a01c1690421080156138b4575b6138ae57815f52600960205264ffffffffff60405f205460c81c1690814210156138915780613843920390420361449b565b815f5260096020526138666001600160801b03600260405f200154168092614587565b90811161387b576001600160801b0391501690565b505f526009602052600260405f20015460801c90565b50505f5260096020526001600160801b03600260405f2001541690565b50505f90565b50428111613811565b805f52600960205260ff600160405f20015460a01c165f146138df5750600490565b805f52600960205260405f205460f81c61394b57805f52600960205264ffffffffff60405f205460a01c16421061394657613919816137dc565b905f5260096020526001600160801b0380600260405f200154169116105f1461394157600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a8b575b80613a6e575b613a5c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a25575b1680613a0d575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556139c9565b613a44835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556139c2565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613976565b506001600160a01b0382161515613970565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613acf57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b3d575b508115613b24575090565b90506001600160a01b03613b383392613342565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b19565b805f526009602052613b80600260405f200161361f565b90805f52600960205260ff600160405f20015460a01c165f14613bae5750602001516001600160801b031690565b90815f52600960205260405f205460f81c613bd05750613bcd906137dc565b90565b613bcd91506001600160801b036040818351169201511690613364565b90613c0e6001600160801b03604084015116602060e0850151015190614364565b916001600160801b0383511660c082015190156142905764ffffffffff81511615614268576020810164ffffffffff815116806141dc575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141ae57505064ffffffffff80421691511690818110156141805750506007549280516001600160801b03169160405192613c9e8461327c565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d04896132b5565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600960205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f8491906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614160575b50600185016007556001600160a01b0360208201511680156135ca57613ff2866001600160a01b0392613951565b166141345761401d6001600160a01b036060830151166001600160801b038451169030903390614441565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614105575b506140fc6001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b61412e906001600160a01b036060880151166001600160a01b0360e08901515116903390614441565b5f614058565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600a60205260405f209064ffffffffff198254161790555f613fc4565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561423a57505064ffffffffff90511664ffffffffff60408301511690818110613c46577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d156142e2573d906142c982613310565b916142d760405193846132ee565b82523d5f602084013e565b606090565b613bcd906142f481613b69565b905f526009602052600260405f20015460801c90613364565b614362926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261435d6064836132ee565b614635565b565b919091604051614373816132d2565b5f81525f6020820152926001600160801b0382169081156144245767016345785d8a000081116143ed576143af6001600160801b039183614587565b16602085019181835211156143d9576001600160801b0391826143d492511690613364565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614435816132d2565b5f81525f602082015290565b9091926001600160a01b036143629481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261435d6084836132ee565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614566578184101561452c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614573570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461462457670de0b6b3a76400008210156145f4577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361465e93169360208151910182865af16146576142b8565b90836146c3565b805190811515918261469f575b50506146745750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612c6d5760200151801590811503612c6d575f8061466b565b9061470057508051156146d857805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614746575b614711575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561470956fea164736f6c634300081a000a"; + hex"60a0604052346103bf57614b786040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478f90816103e9823960805181613ada0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461309f57508063027b67441461307d57806306fdde0314612f89578063081812fc14612f6b578063095ea7b314612e665780631400ecec14612db55780631c1cdd4c14612d2c5780631e99d56914612d0f57806323b872dd14612cf657806340e58ee5146129e1578063425d30dd1461298f57806342842e0e1461296557806342966c681461278857806344267570146127615780634857501f146126eb5780634869e12d146126af5780634cc55e11146121f657806353b15727146120c857806357404b121461200d5780636352211e14611fdd5780636d0cee7514611fdd57806370a0823114611f7257806375829def14611f00578063780a82c814611eb25780637cad6cd114611da65780637de6b1db14611bb15780638659c2701461180d578063894e9a0d1461150b5780638f69b993146114705780639067b6771461141f57806395d89b4114611312578063a22cb4651461125c578063a80fc07114611209578063ab167ccc1461108c578063ad35efd414611019578063b256456914610fc7578063b88d4fde14610f36578063b8a3be6614610f01578063b971302a14610eb1578063bc2be1be14610e60578063c156a11d146109a8578063c87b56dd14610888578063d4dbd20b14610835578063d511609f146107e8578063d975dfed1461079b578063e985e9c514610748578063ea5ead1914610721578063eac8f5b8146106ce578063f590c17614610671578063f851a4401461064b5763fdd46d601461024f575f80fd5b346104d65760603660031901126104d6576004359061026c6131fd565b61027461335f565b9261027d613ad0565b808352600960205260ff600160408520015460a81c161561063a57808352600960205260ff600160408520015460a01c16610628576001600160a01b038216938415610615576001600160801b03811680156106025782855260036020526001600160a01b0360408620541680871415806105f2575b6105d7576001600160801b036103088561431a565b168083116105bc575083865260096020526001600160a01b0360408720541691848752600960205280600260408920015460801c01976001600160801b0389116105a8576103808899878a526009602052600260408b2001906001600160801b036001600160801b031983549260801b169116179055565b8588526009602052610397600260408a2001613652565b6001600160801b036103bb8160208401511692826040818351169201511690613397565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c88614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb91613321565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b8161055391613321565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b602488634e487b7160e01b81526011600452fd5b86606491848763287ecaef60e21b8452600452602452604452fd5b606486888663b34359d360e01b835260045233602452604452fd5b506105fc84613b2a565b156102f3565b6024858463d2aabcd960e01b8252600452fd5b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576004359061073f6131fd565b6102748361431a565b50346104d65760403660031901126104d6576001600160a01b03604061076c6131e7565b92826107766131fd565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d78361431a565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d6576004356108a6816137dc565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa90811561099d578291610916575b60405160208082528190610912908201856131c2565b0390f35b90503d8083833e6109278183613321565b8101906020818303126109955780519067ffffffffffffffff8211610999570181601f820112156109955780519261095e84613343565b9261096c6040519485613321565b848452602085840101116104d657506109129261098f91602080850191016131a1565b5f6108fc565b8280fd5b8380fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d657600435906109c66131fd565b916109cf613ad0565b808252600960205260ff600160408420015460a81c1615610e4e5780825260036020526001600160a01b0360408320541692833303610e3757610a118261431a565b6001600160801b0381169081158015610a99575b5050506001600160a01b03811615610a8657610a49826001600160a01b0392613984565b1680610a625760248383637e27328960e01b8252600452fd5b90838203610a6e578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610aa1613ad0565b848652600960205260ff600160408820015460a81c1615610e2557848652600960205260ff600160408820015460a01c16610e12578615610dff57610dec5783855260036020526001600160a01b036040862054168087141580610ddc575b610dc1576001600160801b03610b158661431a565b16808411610da6575084865260096020526001600160a01b0360408720541692858752600960205280600260408920015460801c016001600160801b0381116105a857610b8b908789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b8587526009602052610ba260026040892001613652565b6001600160801b03610bc68160208401511692826040818351169201511690613397565b161115610d6a575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610c18818688614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610d60575b610cf5575b823314159081610cea575b81610cdf575b50610c75575b80610a25565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610c6f5781610cd491613321565b61099557825f610c6f565b90508214155f610c69565b833b15159150610c63565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610d4b575b5050610c58565b81610d5591613321565b61055e57855f610d44565b50803b1515610c53565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610bce565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610de685613b2a565b15610b00565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610f506131e7565b610f586131fd565b906064359067ffffffffffffffff821161099957366023830112156109995781600401359284610f8785613343565b93610f956040519586613321565b8585523660248783010111610fc35785610fc096602460209301838801378501015260443591613698565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b57611052906138f0565b60405190600581101561106757602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d6576101403660031901126104d6576110a7613ad0565b6110af613634565b9064ffffffffff421680835264ffffffffff6110c9613684565b166111ee575b60e4359064ffffffffff82168203610995570164ffffffffff1660408301526001600160a01b03600435908116929083810361099557506024356001600160a01b0381169081810361099957506044356001600160801b038116908181036104d957506064356001600160a01b0381168091036104d95760843591821515928381036111ea575060a43593841515948581036111e65750604051976111738961327e565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126104d657604051906111ad82613305565b61010435906001600160a01b03821682036104d65760206111de8585858152610124358482015260e0820152613c20565b604051908152f35b8780fd5b8680fd5b64ffffffffff6111fc613684565b82011660208401526110cf565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576112766131e7565b60243590811515809203610995576001600160a01b03169081156112e657338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611415575b602084108114611401578386529081156113da575060011461137d575b6109128461136981860382613321565b6040519182916020835260208301906131c2565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106113c05750909150810160200161136982611359565b9192600181602092548385880101520191019092916113a7565b60ff191660208087019190915292151560051b850190920192506113699150839050611359565b602483634e487b7160e01b81526022600452fd5b92607f169261133c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b576114a9906138f0565b90600582101590816114ea57600283149182156114fe575b82156114d5575b6020836040519015158152f35b9091506114ea57506004602091145f806114c8565b80634e487b7160e01b602492526021600452fd5b50600383149150806114c1565b50346104d65760203660031901126104d6576004359080610160604051611531816132cb565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611574613634565b6101408201520152818152600960205260ff600160408320015460a81c16156106bd5781815260096020526040812091604051906115b1826132e8565b8354906001600160a01b0382168352602083019464ffffffffff8360a01c168652604084019464ffffffffff8460c81c168652606085019060ff8560f01c1615158252608086019460f81c1515855260018301549560a08101966001600160a01b038116885260c082019660ff8260a01c1615158852611652600260e085019760ff8560a81c161515895260ff61010087019560b01c161515855201613652565b6101208401908152611663886138f0565b60058110156117f9576002146117f1575b5198516001600160a01b031693878152600a602052604081205464ffffffffff169a5164ffffffffff1695511515925115159851151596511515978152600360205260409020546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516116e9816132cb565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b848652611674565b602486634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff8111610fc35761183f90369060040161324d565b90611848613ad0565b82915b808310611856578380f35b611861838284613610565b359261186b613ad0565b838552600960205260ff600160408720015460a81c1615611b9f578385526009602052604085206001015460a01c60ff16156118b45760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611b8d576118e9815f5260096020526001600160a01b0360405f205416331490565b15611b77576118f78161380f565b90808652600960205261190f60026040882001613652565b916001600160801b038351166001600160801b0382161015611b6457818752600960205260ff604088205460f01c1615611b515790611966826001600160801b036020818796818d99511603169501511690613397565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611b2c575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a906001600160a01b03600160408d2001541694611a688b8588614340565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611ad4575b505050505050600101919061184b565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b17575b80808080611ac4565b81611b2191613321565b61099957835f611b0e565b818552600960205260016040862001600160a01b60ff60a01b198254161790556119c7565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590611bcf613ad0565b818152600960205260ff600160408320015460a81c16156106bd57611bf3826138f0565b6005811015611d925760048103611c175750602491634a5541ef60e01b8252600452fd5b60038103611c32575060249163fe19f19f60e01b8252600452fd5b600214611d8057611c57825f5260096020526001600160a01b0360405f205416331490565b15611d6a57818152600960205260ff604082205460f01c1615611d5857818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611cfd575050f35b813b15611d545782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611d435750f35b81611d4d91613321565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b038116809103610fc3576001600160a01b03825416338103611e83575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e6f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff9352600a8452205416604051908152f35b50346104d65760203660031901126104d657611f1a6131e7565b9080546001600160a01b038116338103611e8357506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b03611f946131e7565b168015611fb1578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020611ffc6004356137dc565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d6576004359061202b613634565b50818152600960205260ff600160408320015460a81c16156106bd57816060928252600960205264ffffffffff6040818185205460a01c1693838152600a6020528282822054169381526009602052205460c81c16906040519261208e846132af565b8352602083015260408201526120c6604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b50346104d6576101603660031901126104d6576120e3613ad0565b604051906120f08261327e565b6120f86131e7565b82526121026131fd565b602083015261210f61335f565b60408301526064356001600160a01b0381168103610fc35760608301526084358015158103610fc357608083015260a4358015158103610fc35760a083015260603660c31901126104d657604051612166816132af565b60c43564ffffffffff8116810361099557815260e43564ffffffffff811681036109955760208201526101043564ffffffffff8116810361099557604082015260c08301526040610123193601126104d657604051906121c582613305565b61012435906001600160a01b03821682036104d65760206111de8585858152610144358482015260e0820152613c20565b50346104d65760403660031901126104d65760043567ffffffffffffffff8111610fc35761222890369060040161324d565b9060243567ffffffffffffffff81116109995761224990369060040161324d565b612251613ad0565b80840361267f57845b848110612265578580f35b612270818686613610565b3561227c828787613610565b35875260036020526001600160a01b036040882054169061229e838587613610565b356001600160801b03811680820361267b576122b8613ad0565b828a52600960205260ff600160408c20015460a81c161561266957828a52600960205260ff600160408c20015460a01c1661265657831561264357801561263057828a5260036020526001600160a01b0360408b205416908185141580612620575b612605576001600160801b0361232f8561431a565b168082116125ea5750908a91848352600960205280600260406001600160a01b03818720541695888152600960205220015460801c016001600160801b0381116125d657906123ad86959493928e989789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b84875260096020526123c460026040892001613652565b6001600160801b036123e88160208401511692826040818351169201511690613397565b16111561259a575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461243a818688614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580612590575b612525575b81331415908161251a575b8161250f575b5061249e575b505050505060010161225a565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16124fa575b808080612491565b8161250491613321565b61055e57855f6124f2565b90508114155f61248b565b823b15159150612485565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af161257b575b505061247a565b8161258591613321565b61055e57855f612574565b50803b1515612475565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556123f0565b60248d634e487b7160e01b81526011600452fd5b8b906064928663287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061262a84613b2a565b1561231a565b60248a8463d2aabcd960e01b8252600452fd5b60248a84630ff7ee2d60e31b8252600452fd5b60248a84634a5541ef60e01b8252600452fd5b60248a8462b8e7e760e51b8252600452fd5b8980fd5b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d783613b9c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5780612726836138f0565b926005841015611d9257600260209403612747575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061273b565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d6576004356127a5613ad0565b808252600960205260ff600160408420015460a81c161561107b57808252600960205260ff600160408420015460a01c161561293a576127e481613b2a565b156129245780825260036020526001600160a01b0360408320541615158061291d575b80612900575b6128ee577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b0360408320541680159081156128b7575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506128a5575080f35b637e27328960e01b8252600452602490fd5b6128d6835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561285b565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c161561280d565b5081612807565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d657610fc061297736613213565b9060405192612987602085613321565b858452613698565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612c6d576020366003190112612c6d57600435906129ff613ad0565b815f52600960205260ff600160405f20015460a81c1615612ce457815f52600960205260ff600160405f20015460a01c165f14612a495750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612cd257612a7c815f5260096020526001600160a01b0360405f205416331490565b15612cbc57612a8a8161380f565b90805f526009602052612aa2600260405f2001613652565b916001600160801b038351166001600160801b0382161015612ca957815f52600960205260ff60405f205460f01c1615612c9657806001600160801b03602081612af6948188511603169501511690613397565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612c71575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612be16001600160a01b03600160405f2001541694611a688b8588614340565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612c18578580f35b813b15612c6d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c5a575b808080808580f35b612c6691505f90613321565b5f80612c52565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612b40565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612c6d57612d0d612d0736613213565b916133cb565b005b34612c6d575f366003190112612c6d576020600754604051908152f35b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da457612d64906138f0565b6005811015612d90578060209115908115612d85575b506040519015158152f35b600191501482612d7a565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da4576020905f90805f526009835260ff60405f205460f01c1680612e4a575b612e18575b506001600160801b0360405191168152f35b612e449150805f5260098352612e3e6001600160801b03600260405f200154169161380f565b90613397565b82612e06565b50805f526009835260ff600160405f20015460a01c1615612e01565b34612c6d576040366003190112612c6d57612e7f6131e7565b602435612e8b816137dc565b33151580612f58575b80612f25575b612ef95781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612e9a565b50336001600160a01b0382161415612e94565b34612c6d576020366003190112612c6d576020611ffc600435613375565b34612c6d575f366003190112612c6d576040515f6001548060011c90600181168015613073575b60208310811461305f5782855290811561303b5750600114612fdd575b6109128361136981850382613321565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061302157509091508101602001611369612fcd565b919260018160209254838588010152019101909291613009565b60ff191660208086019190915291151560051b840190910191506113699050612fcd565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612fb0565b34612c6d575f366003190112612c6d57602060405167016345785d8a00008152f35b34612c6d576020366003190112612c6d57600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612c6d57817f490649060000000000000000000000000000000000000000000000000000000060209314908115613113575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613177575b811561314d575b508361310c565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613146565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061313f565b5f5b8381106131b25750505f910152565b81810151838201526020016131a3565b906020916131db815180928185528580860191016131a1565b601f01601f1916010190565b600435906001600160a01b0382168203612c6d57565b602435906001600160a01b0382168203612c6d57565b6060906003190112612c6d576004356001600160a01b0381168103612c6d57906024356001600160a01b0381168103612c6d579060443590565b9181601f84011215612c6d5782359167ffffffffffffffff8311612c6d576020808501948460051b010111612c6d57565b610100810190811067ffffffffffffffff82111761329b57604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761329b57604052565b610180810190811067ffffffffffffffff82111761329b57604052565b610140810190811067ffffffffffffffff82111761329b57604052565b6040810190811067ffffffffffffffff82111761329b57604052565b90601f8019910116810190811067ffffffffffffffff82111761329b57604052565b67ffffffffffffffff811161329b57601f01601f191660200190565b604435906001600160801b0382168203612c6d57565b61337e816137dc565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116133b757565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156135fd57815f5260036020526001600160a01b0360405f2054161515806135f5575b806135d8575b6135c5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613510575b6001600160a01b039350856134d9575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036134c157505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6134f8825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613460565b919290508061356e575b1561352757828291613450565b828461353f57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b50338414801561359c575b8061351a5750825f526005602052336001600160a01b0360405f2054161461351a565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613579565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615613400565b5060016133fa565b633250574960e11b5f525f60045260245ffd5b91908110156136205760051b0190565b634e487b7160e01b5f52603260045260245ffd5b60405190613641826132af565b5f6040838281528260208201520152565b9060405161365f816132af565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff81168103612c6d5790565b906136a48382846133cb565b803b6136b1575b50505050565b6020916136f76001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906131c2565b03815f865af15f918161377f575b5061373357506137136142eb565b8051908161372e5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361376d57505f8080806136ab565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116137d4575b8161379b60209383613321565b81010312612c6d57517fffffffff0000000000000000000000000000000000000000000000000000000081168103612c6d57905f613705565b3d915061378e565b805f5260036020526001600160a01b0360405f2054169081156137fd575090565b637e27328960e01b5f5260045260245ffd5b805f52600a60205264ffffffffff60405f205416815f52600960205264ffffffffff60405f205460a01c1690421080156138e7575b6138e157815f52600960205264ffffffffff60405f205460c81c1690814210156138c4578061387692039042036144ce565b815f5260096020526138996001600160801b03600260405f2001541680926145ba565b9081116138ae576001600160801b0391501690565b505f526009602052600260405f20015460801c90565b50505f5260096020526001600160801b03600260405f2001541690565b50505f90565b50428111613844565b805f52600960205260ff600160405f20015460a01c165f146139125750600490565b805f52600960205260405f205460f81c61397e57805f52600960205264ffffffffff60405f205460a01c1642106139795761394c8161380f565b905f5260096020526001600160801b0380600260405f200154169116105f1461397457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613abe575b80613aa1575b613a8f577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a58575b1680613a40575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556139fc565b613a77835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556139f5565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c16156139a9565b506001600160a01b03821615156139a3565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0257565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b70575b508115613b57575090565b90506001600160a01b03613b6b3392613375565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b4c565b805f526009602052613bb3600260405f2001613652565b90805f52600960205260ff600160405f20015460a01c165f14613be15750602001516001600160801b031690565b90815f52600960205260405f205460f81c613c035750613c009061380f565b90565b613c0091506001600160801b036040818351169201511690613397565b90613c416001600160801b03604084015116602060e0850151015190614397565b916001600160801b0383511660c082015190156142c35764ffffffffff8151161561429b576020810164ffffffffff8151168061420f575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e157505064ffffffffff80421691511690818110156141b35750506007549280516001600160801b03169160405192613cd1846132af565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d37896132e8565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600960205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fb791906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614193575b50600185016007556001600160a01b0360208201511680156135fd57614025866001600160a01b0392613984565b16614167576140506001600160a01b036060830151166001600160801b038451169030903390614474565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614138575b5061412f6001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614161906001600160a01b036060880151166001600160a01b0360e08901515116903390614474565b5f61408b565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600a60205260405f209064ffffffffff198254161790555f613ff7565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561426d57505064ffffffffff90511664ffffffffff60408301511690818110613c79577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614315573d906142fc82613343565b9161430a6040519384613321565b82523d5f602084013e565b606090565b613c009061432781613b9c565b905f526009602052600260405f20015460801c90613397565b614395926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614390606483613321565b614668565b565b9190916040516143a681613305565b5f81525f6020820152926001600160801b0382169081156144575767016345785d8a00008111614420576143e26001600160801b0391836145ba565b166020850191818352111561440c576001600160801b03918261440792511690613397565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446881613305565b5f81525f602082015290565b9091926001600160a01b036143959481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614390608483613321565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614599578184101561455f57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145a6570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465757670de0b6b3a7640000821015614627577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469193169360208151910182865af161468a6142eb565b90836146f6565b80519081151591826146d2575b50506146a75750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612c6d5760200151801590811503612c6d575f8061469e565b90614733575080511561470b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614779575b614744575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473c56fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e457614ebd6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614aaf908161040e823960805181613eb8015260a051818181612f4e0152613f610152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613445565b604435926001600160801b0384169384810361063957610295613eae565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614706565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61472c565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a20016139fc565b6001600160801b036103bb8160208401511692826040818351169201511690613630565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c8861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135bc565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135bc565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e8846145e1565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613445565b61073a83614706565b92610743613eae565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614706565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b03604061082861342f565b9282610832613445565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614706565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613b93565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561340a565b0390f35b90503d8083833e6109e381836135bc565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a846135de565b92610a2860405194856135bc565b848452602085840101116104d657506109ce92610a4b91602080850191016133e9565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613445565b91610a87613eae565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614706565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d62565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613eae565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614706565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61472c565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d600260408920016139fc565b6001600160801b03610c718160208401511692826040818351169201511690613630565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc381868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135bc565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135bc565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e91856145e1565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb61342f565b611003613445565b906064359067ffffffffffffffff821161063957366023830112156106395781600401359284611032856135de565b9361104060405195866135bc565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a4f565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613cce565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a461342f565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135bc565b60405191829160208352602083019061340a565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613cce565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613eae565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138bb565b956114cc60405197886135bc565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138bb565b9261150360405194856135bc565b808452601f19611512826138bb565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bc6565b51511664ffffffffff80602061154d85613bc6565b510151168601166040519161156183613567565b8252602082015261157186613bc6565b5261157b85613bc6565b5060015b8281106116555750505061159584600401613a2e565b906115a260248601613a2e565b906115af6044870161395c565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a42565b948161160260a48c01613a42565b976040519d8e613536565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101613909565b610100820152613f08565b604051908152f35b806001600160801b0361166a60019385613bd3565b51511664ffffffffff8060206116835f1986018c613bd3565b510151168160206116948689613bd3565b510151160116604051916116a783613567565b825260208201526116b88289613bd3565b526116c38188613bd3565b500161157f565b6020906040516116d981613567565b5f81525f8382015282828901015201611515565b60206040916116fc36856138d3565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d81613583565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135a0565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c1615158952016139fc565b6101208c019081526118818a613cce565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c613583565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b0198895261195490613988565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce916134da565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134a9565b90611a96613eae565b82915b808310611aa4578380f35b611aaf838284613938565b3592611ab9613eae565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613be7565b908086526009602052611b5d600260408820016139fc565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613630565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b858861488a565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135bc565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a60205220613988565b6040519182916020835260208301906134da565b50346104d65760203660031901126104d65760043590611e79613eae565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613cce565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135bc565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65761217661342f565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f061342f565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613b93565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d65760043590612287613970565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d983613567565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134a9565b9060243567ffffffffffffffff8111610639576123549036906004016134a9565b9261235d613eae565b83810361276357845b818110612371578580f35b61237c818386613938565b35612388828487613938565b35875260036020526001600160a01b03604088205416906123b26123ad848988613938565b61395c565b6123ba613eae565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614706565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61472c565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c0600260408920016139fc565b6001600160801b036124e48160208401511692826040818351169201511690613630565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461253681868861488a565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135bc565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135bc565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b50612712846145e1565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614653565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613cce565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613eae565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c8816145e1565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b3661346f565b9060405192612a6b6020856135bc565b858452613a4f565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613eae565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613be7565b90805f526009602052612b86600260405f20016139fc565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613630565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b858861488a565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135bc565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613eae565b604051612e2081613536565b612e2c8260040161345b565b8152612e3a6024830161345b565b6020820152612e4b604483016135fa565b604082015260648201356001600160a01b0381168103612d51576060820152612e7660848301613529565b6080820152612e8760a48301613529565b60a0820152612e9860c483016138a9565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138bb565b90612edc60405192836135bc565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e0840152610104369101613909565b6020604091612f2c36896138d3565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f823661346f565b91613664565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613cce565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613be7565b90613630565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa61342f565b60243561310681613b93565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d5157602061225860043561360e565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135bc565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f80ac58cd00000000000000000000000000000000000000000000000000000000602093149081156133bf575b8115613395575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150148361338e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613387565b5f5b8381106133fa5750505f910152565b81810151838201526020016133eb565b90602091613423815180928185528580860191016133e9565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b8181106134f75750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134ea565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761355357604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761355357604052565b610180810190811067ffffffffffffffff82111761355357604052565b6060810190811067ffffffffffffffff82111761355357604052565b90601f8019910116810190811067ffffffffffffffff82111761355357604052565b67ffffffffffffffff811161355357601f01601f191660200190565b35906001600160801b0382168203612d5157565b61361781613b93565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161365057565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b0316801561389657815f5260036020526001600160a01b0360405f20541615158061388e575b80613871575b61385e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137a9575b6001600160a01b03935085613772575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361375a57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613791825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136f9565b9192905080613807575b156137c0578282916136e9565b82846137d857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613835575b806137b35750825f526005602052336001600160a01b0360405f205416146137b3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613812565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615613699565b506001613693565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135535760051b60200190565b9190826040910312612d51576040516138eb81613567565b60206139048183956138fc816135fa565b8552016138a9565b910152565b9190826040910312612d515760405161392181613567565b602080829461392f8161345b565b84520135910152565b91908110156139485760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b6040519061397d82613567565b5f6020838281520152565b908154613994816138bb565b926139a260405194856135bc565b81845260208401905f5260205f205f915b8383106139c05750505050565b6001602081926040516139d281613567565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139b3565b90604051613a09816135a0565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a5b838284613664565b803b613a68575b50505050565b602091613aae6001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061340a565b03815f865af15f9181613b36575b50613aea5750613aca6146d7565b80519081613ae55782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b2457505f808080613a62565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613b8b575b81613b52602093836135bc565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613abc565b3d9150613b45565b805f5260036020526001600160a01b0360405f205416908115613bb4575090565b637e27328960e01b5f5260045260245ffd5b8051156139485760200190565b80518210156139485760209160051b010190565b9064ffffffffff421691805f52600a602052613c0560405f20613988565b908364ffffffffff6020613c1885613bc6565b5101511611613cc757805f5260096020528364ffffffffff60405f205460c81c161115613ca857506001600160801b03613c5182613bc6565b515116916001925b8251841015613ca1578464ffffffffff6020613c758787613bd3565b5101511611613ca1576001600160801b0360019181613c948787613bd3565b5151160116930192613c59565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613cf05750600490565b805f52600960205260405f205460f81c613d5c57805f52600960205264ffffffffff60405f205460a01c164210613d5757613d2a81613be7565b905f5260096020526001600160801b0380600260405f200154169116105f14613d5257600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e9c575b80613e7f575b613e6d577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e36575b1680613e1e575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613dda565b613e55835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613dd3565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613d87565b506001600160a01b0382161515613d81565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613ee057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f2a6001600160801b03604084015116602061010085015101519061474c565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145b95780156145915781518015614569577f0000000000000000000000000000000000000000000000000000000000000000811161453e575064ffffffffff6020613f9884613bc6565b510151168110156144fa57505f905f905f81515f905b808210614472575050505064ffffffffff804216911690818110156144445750506001600160801b03169081810361441657505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061417a8751975f19890190613bd3565b51015160c81b169360a01b169116171785555f5b818110614364575050600187016007556001600160a01b036020830151168015613896576141c4886001600160a01b0392613d62565b166143385786826142126001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b038551169030903390614829565b6001600160801b0360208401511680614308575b506001600160a01b03815116946142fd6142df6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142848b613567565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134da565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614332906001600160a01b036060840151166001600160a01b036101008501515116903390614829565b5f614226565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f209061437f8160e0870151613bd3565b51825492680100000000000000008410156135535760018401808255841015613948576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161418e565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614496906001600160801b0361448d8588613bd3565b5151169061472c565b9364ffffffffff8060206144aa8685613bd3565b510151169416808511156144c657506001849301909291613fae565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061450b84613bc6565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614627575b50811561460e575090565b90506001600160a01b03614622339261360e565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614603565b805f52600960205261466a600260405f20016139fc565b90805f52600960205260ff600160405f20015460a01c165f146146985750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ba57506146b790613be7565b90565b6146b791506001600160801b036040818351169201511690613630565b3d15614701573d906146e8826135de565b916146f660405193846135bc565b82523d5f602084013e565b606090565b6146b79061471381614653565b905f526009602052600260405f20015460801c90613630565b906001600160801b03809116911601906001600160801b03821161365057565b91909160405161475b81613567565b5f81525f6020820152926001600160801b03821690811561480c5767016345785d8a000081116147d5576147976001600160801b039183614968565b16602085019181835211156147c1576001600160801b0391826147bc92511690613630565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161481d81613567565b5f81525f602082015290565b9091926001600160a01b036148889481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148836084836135bc565b6148da565b565b614888926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148836064836135bc565b5f806001600160a01b0361490393169360208151910182865af16148fc6146d7565b9083614a16565b8051908115159182614944575b50506149195750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614910565b9091905f1983820983820291828083109203918083039214614a0557670de0b6b3a76400008210156149d5577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a535750805115614a2b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a99575b614a64575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a5c56fea164736f6c634300081a000a"; + hex"60c0604052346103e457614ef06060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614ae2908161040e823960805181613eeb015260a051818181612f4e0152613f940152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613478565b604435926001600160801b0384169384810361063957610295613ee1565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614739565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61475f565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a2001613a2f565b6001600160801b036103bb8160208401511692826040818351169201511690613663565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135ef565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135ef565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e884614614565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613478565b61073a83614739565b92610743613ee1565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614739565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b036040610828613462565b9282610832613478565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614739565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613bc6565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561343d565b0390f35b90503d8083833e6109e381836135ef565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a84613611565b92610a2860405194856135ef565b848452602085840101116104d657506109ce92610a4b916020808501910161341c565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613478565b91610a87613ee1565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614739565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d95565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613ee1565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614739565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61475f565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d60026040892001613a2f565b6001600160801b03610c718160208401511692826040818351169201511690613663565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc38186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135ef565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135ef565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e9185614614565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb613462565b611003613478565b906064359067ffffffffffffffff82116106395736602383011215610639578160040135928461103285613611565b9361104060405195866135ef565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a82565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613d01565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a4613462565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135ef565b60405191829160208352602083019061343d565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613d01565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613ee1565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138ee565b956114cc60405197886135ef565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138ee565b9261150360405194856135ef565b808452601f19611512826138ee565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bf9565b51511664ffffffffff80602061154d85613bf9565b51015116860116604051916115618361359a565b8252602082015261157186613bf9565b5261157b85613bf9565b5060015b8281106116555750505061159584600401613a61565b906115a260248601613a61565b906115af6044870161398f565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a75565b948161160260a48c01613a75565b976040519d8e613569565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161393c565b610100820152613f3b565b604051908152f35b806001600160801b0361166a60019385613c06565b51511664ffffffffff8060206116835f1986018c613c06565b510151168160206116948689613c06565b510151160116604051916116a78361359a565b825260208201526116b88289613c06565b526116c38188613c06565b500161157f565b6020906040516116d98161359a565b5f81525f8382015282828901015201611515565b60206040916116fc3685613906565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d816135b6565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135d3565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c161515895201613a2f565b6101208c019081526118818a613d01565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c6135b6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611954906139bb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce9161350d565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134dc565b90611a96613ee1565b82915b808310611aa4578380f35b611aaf83828461396b565b3592611ab9613ee1565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613c1a565b908086526009602052611b5d60026040882001613a2f565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613663565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b85886148bd565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135ef565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a602052206139bb565b60405191829160208352602083019061350d565b50346104d65760203660031901126104d65760043590611e79613ee1565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613d01565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135ef565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d657612176613462565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f0613462565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613bc6565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d657600435906122876139a3565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d98361359a565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134dc565b9060243567ffffffffffffffff8111610639576123549036906004016134dc565b9261235d613ee1565b83810361276357845b818110612371578580f35b61237c81838661396b565b3561238882848761396b565b35875260036020526001600160a01b03604088205416906123b26123ad84898861396b565b61398f565b6123ba613ee1565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614739565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61475f565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c060026040892001613a2f565b6001600160801b036124e48160208401511692826040818351169201511690613663565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d20015416946125368186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135ef565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135ef565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061271284614614565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614686565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613d01565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613ee1565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c881614614565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b366134a2565b9060405192612a6b6020856135ef565b858452613a82565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613ee1565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613c1a565b90805f526009602052612b86600260405f2001613a2f565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613663565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b85886148bd565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135ef565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613ee1565b604051612e2081613569565b612e2c8260040161348e565b8152612e3a6024830161348e565b6020820152612e4b6044830161362d565b604082015260648201356001600160a01b0381168103612d51576060820152612e766084830161355c565b6080820152612e8760a4830161355c565b60a0820152612e9860c483016138dc565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138ee565b90612edc60405192836135ef565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e084015261010436910161393c565b6020604091612f2c3689613906565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f82366134a2565b91613697565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613d01565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613c1a565b90613663565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa613462565b60243561310681613bc6565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d51576020612258600435613641565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135ef565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f49064906000000000000000000000000000000000000000000000000000000006020931490811561338e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133f2575b81156133c8575b5083613387565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836133c1565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506133ba565b5f5b83811061342d5750505f910152565b818101518382015260200161341e565b906020916134568151809281855285808601910161341c565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b81811061352a5750505090565b825180516001600160801b0316855260209081015164ffffffffff16818601526040909401939092019160010161351d565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761358657604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761358657604052565b610180810190811067ffffffffffffffff82111761358657604052565b6060810190811067ffffffffffffffff82111761358657604052565b90601f8019910116810190811067ffffffffffffffff82111761358657604052565b67ffffffffffffffff811161358657601f01601f191660200190565b35906001600160801b0382168203612d5157565b61364a81613bc6565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161368357565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156138c957815f5260036020526001600160a01b0360405f2054161515806138c1575b806138a4575b613891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137dc575b6001600160a01b039350856137a5575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361378d57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6137c4825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561372c565b919290508061383a575b156137f35782829161371c565b828461380b57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613868575b806137e65750825f526005602052336001600160a01b0360405f205416146137e6565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613845565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c16156136cc565b5060016136c6565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135865760051b60200190565b9190826040910312612d515760405161391e8161359a565b602061393781839561392f8161362d565b8552016138dc565b910152565b9190826040910312612d51576040516139548161359a565b60208082946139628161348e565b84520135910152565b919081101561397b5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b604051906139b08261359a565b5f6020838281520152565b9081546139c7816138ee565b926139d560405194856135ef565b81845260208401905f5260205f205f915b8383106139f35750505050565b600160208192604051613a058161359a565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139e6565b90604051613a3c816135d3565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a8e838284613697565b803b613a9b575b50505050565b602091613ae16001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061343d565b03815f865af15f9181613b69575b50613b1d5750613afd61470a565b80519081613b185782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b5757505f808080613a95565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613bbe575b81613b85602093836135ef565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613aef565b3d9150613b78565b805f5260036020526001600160a01b0360405f205416908115613be7575090565b637e27328960e01b5f5260045260245ffd5b80511561397b5760200190565b805182101561397b5760209160051b010190565b9064ffffffffff421691805f52600a602052613c3860405f206139bb565b908364ffffffffff6020613c4b85613bf9565b5101511611613cfa57805f5260096020528364ffffffffff60405f205460c81c161115613cdb57506001600160801b03613c8482613bf9565b515116916001925b8251841015613cd4578464ffffffffff6020613ca88787613c06565b5101511611613cd4576001600160801b0360019181613cc78787613c06565b5151160116930192613c8c565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613d235750600490565b805f52600960205260405f205460f81c613d8f57805f52600960205264ffffffffff60405f205460a01c164210613d8a57613d5d81613c1a565b905f5260096020526001600160801b0380600260405f200154169116105f14613d8557600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ecf575b80613eb2575b613ea0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e69575b1680613e51575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613e0d565b613e88835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613e06565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613dba565b506001600160a01b0382161515613db4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613f1357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f5d6001600160801b03604084015116602061010085015101519061477f565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145ec5780156145c4578151801561459c577f00000000000000000000000000000000000000000000000000000000000000008111614571575064ffffffffff6020613fcb84613bf9565b5101511681101561452d57505f905f905f81515f905b8082106144a5575050505064ffffffffff804216911690818110156144775750506001600160801b03169081810361444957505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206141ad8751975f19890190613c06565b51015160c81b169360a01b169116171785555f5b818110614397575050600187016007556001600160a01b0360208301511680156138c9576141f7886001600160a01b0392613d95565b1661436b5786826142456001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061485c565b6001600160801b036020840151168061433b575b506001600160a01b03815116946143306143126001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142b78b61359a565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061350d565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614365906001600160a01b036060840151166001600160a01b03610100850151511690339061485c565b5f614259565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f20906143b28160e0870151613c06565b5182549268010000000000000000841015613586576001840180825584101561397b576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016141c1565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b91935091936144c9906001600160801b036144c08588613c06565b5151169061475f565b9364ffffffffff8060206144dd8685613c06565b510151169416808511156144f957506001849301909291613fe1565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061453e84613bf9565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561465a575b508115614641575090565b90506001600160a01b036146553392613641565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614636565b805f52600960205261469d600260405f2001613a2f565b90805f52600960205260ff600160405f20015460a01c165f146146cb5750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ed57506146ea90613c1a565b90565b6146ea91506001600160801b036040818351169201511690613663565b3d15614734573d9061471b82613611565b9161472960405193846135ef565b82523d5f602084013e565b606090565b6146ea9061474681614686565b905f526009602052600260405f20015460801c90613663565b906001600160801b03809116911601906001600160801b03821161368357565b91909160405161478e8161359a565b5f81525f6020820152926001600160801b03821690811561483f5767016345785d8a00008111614808576147ca6001600160801b03918361499b565b16602085019181835211156147f4576001600160801b0391826147ef92511690613663565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516148508161359a565b5f81525f602082015290565b9091926001600160a01b036148bb9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148b66084836135ef565b61490d565b565b6148bb926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148b66064836135ef565b5f806001600160a01b0361493693169360208151910182865af161492f61470a565b9083614a49565b8051908115159182614977575b505061494c5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614943565b9091905f1983820983820291828083109203918083039214614a3857670de0b6b3a7640000821015614a08577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a865750805115614a5e57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614acc575b614a97575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a8f56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601781527f4e6f6e2d416c7068616e756d657269632053796d626f6c000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 7a98bd10b..7adc805d7 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { ISablierV2Recipient } from "../interfaces/hooks/ISablierV2Recipient.sol"; @@ -199,6 +200,11 @@ abstract contract SablierV2Lockup is streamedAmount = _streamedAmountOf(streamId); } + /// @inheritdoc ERC721 + function supportsInterface(bytes4 interfaceId) public view override(ERC721, IERC165) returns (bool) { + return interfaceId == 0x49064906 || super.supportsInterface(interfaceId); + } + /// @inheritdoc ERC721 function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri) { // Check: the stream NFT exists. diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index e08fa8763..3017ef905 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -37,6 +37,9 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); + // {SablierV2Lockup.supportsInterface} + assertTrue(constructedLockupDynamic.supportsInterface(0x49064906), "eip4906 interface"); + // {SablierV2LockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index 42db1d881..5ee4c5032 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -33,5 +33,8 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte address actualNFTDescriptor = address(constructedLockupLinear.nftDescriptor()); address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); + + // {SablierV2Lockup.supportsInterface} + assertTrue(constructedLockupLinear.supportsInterface(0x49064906), "eip4906 interface"); } } diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol index ce5481180..3a0cc8b54 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -37,6 +37,9 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); + // {SablierV2Lockup.supportsInterface} + assertTrue(constructedLockupTranched.supportsInterface(0x49064906), "eip4906 interface"); + // {SablierV2lockupTranched.constructor} uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); uint256 expectedMaxTrancheCount = defaults.MAX_TRANCHE_COUNT(); From 1ae58eb44230e93b055b84df6343156738365bb8 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 18 Jun 2024 23:32:13 +0300 Subject: [PATCH 118/132] refactor: inherit IERC-4906 in abstract (#948) * refactor: inherit IERC-4906 in interface * refactor: import libraries in alphabetical order --------- Co-authored-by: smol-ninja --- src/abstracts/SablierV2Lockup.sol | 7 +++---- src/interfaces/ISablierV2Lockup.sol | 2 ++ test/integration/concrete/lockup-dynamic/constructor.t.sol | 2 +- test/integration/concrete/lockup-linear/constructor.t.sol | 2 +- .../integration/concrete/lockup-tranched/constructor.t.sol | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 7adc805d7..7a2ad5c91 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.22; -import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; @@ -23,8 +22,7 @@ import { NoDelegateCall } from "./NoDelegateCall.sol"; abstract contract SablierV2Lockup is NoDelegateCall, // 0 inherited components Adminable, // 1 inherited components - IERC4906, // 2 inherited components - ISablierV2Lockup, // 4 inherited components + ISablierV2Lockup, // 7 inherited components ERC721 // 6 inherited components { using SafeERC20 for IERC20; @@ -201,7 +199,8 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ERC721 - function supportsInterface(bytes4 interfaceId) public view override(ERC721, IERC165) returns (bool) { + function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721) returns (bool) { + // 0x49064906 is the ERC-165 interface ID required by ERC-4906 return interfaceId == 0x49064906 || super.supportsInterface(interfaceId); } diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 28183b65f..6616ad569 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; @@ -13,6 +14,7 @@ import { ISablierV2NFTDescriptor } from "./ISablierV2NFTDescriptor.sol"; /// @notice Common logic between all Sablier V2 Lockup contracts. interface ISablierV2Lockup is IAdminable, // 0 inherited components + IERC4906, // 2 inherited components IERC721Metadata // 2 inherited components { /*////////////////////////////////////////////////////////////////////////// diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/integration/concrete/lockup-dynamic/constructor.t.sol index 3017ef905..89bb8c07f 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/integration/concrete/lockup-dynamic/constructor.t.sol @@ -38,7 +38,7 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); // {SablierV2Lockup.supportsInterface} - assertTrue(constructedLockupDynamic.supportsInterface(0x49064906), "eip4906 interface"); + assertTrue(constructedLockupDynamic.supportsInterface(0x49064906), "ERC-4906 interface ID"); // {SablierV2LockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/integration/concrete/lockup-linear/constructor.t.sol index 5ee4c5032..323f5fb60 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/integration/concrete/lockup-linear/constructor.t.sol @@ -35,6 +35,6 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); // {SablierV2Lockup.supportsInterface} - assertTrue(constructedLockupLinear.supportsInterface(0x49064906), "eip4906 interface"); + assertTrue(constructedLockupLinear.supportsInterface(0x49064906), "ERC-4906 interface ID"); } } diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/integration/concrete/lockup-tranched/constructor.t.sol index 3a0cc8b54..5bf824fb5 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/integration/concrete/lockup-tranched/constructor.t.sol @@ -38,9 +38,9 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); // {SablierV2Lockup.supportsInterface} - assertTrue(constructedLockupTranched.supportsInterface(0x49064906), "eip4906 interface"); + assertTrue(constructedLockupTranched.supportsInterface(0x49064906), "ERC-4906 interface ID"); - // {SablierV2lockupTranched.constructor} + // {SablierV2LockupTranched.constructor} uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); uint256 expectedMaxTrancheCount = defaults.MAX_TRANCHE_COUNT(); assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_TRANCHE_COUNT"); From 94373aefc0c8d7c5374e215db67c9b34963d60ba Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 19 Jun 2024 13:31:59 +0300 Subject: [PATCH 119/132] refactor: rename alphanumeric function (#949) * refactor: rename alphanumeric function * chore: update precompiles --------- Co-authored-by: andreivladbrg --- precompiles/Precompiles.sol | 2 +- src/SablierV2NFTDescriptor.sol | 8 +- .../isAlphanumericWithSpaces.t.sol | 100 ++++++++++++++++++ .../isAlphanumericWithSpaces.tree} | 6 +- .../is-alphanumeric/isAlphanumeric.t.sol | 100 ------------------ .../safe-asset-symbol/safeAssetSymbol.t.sol | 2 +- ...c.t.sol => isAlphanumericWithSpaces.t.sol} | 12 +-- test/mocks/NFTDescriptorMock.sol | 4 +- 8 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol rename test/integration/concrete/nft-descriptor/{is-alphanumeric/isAlphanumeric.tree => is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree} (56%) delete mode 100644 test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol rename test/integration/fuzz/nft-descriptor/{isAlphanumeric.t.sol => isAlphanumericWithSpaces.t.sol} (74%) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index b7040ede5..859be7ce4 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -32,7 +32,7 @@ contract Precompiles { bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c0604052346103e457614ef06060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614ae2908161040e823960805181613eeb015260a051818181612f4e0152613f940152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613478565b604435926001600160801b0384169384810361063957610295613ee1565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614739565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61475f565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a2001613a2f565b6001600160801b036103bb8160208401511692826040818351169201511690613663565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135ef565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135ef565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e884614614565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613478565b61073a83614739565b92610743613ee1565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614739565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b036040610828613462565b9282610832613478565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614739565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613bc6565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561343d565b0390f35b90503d8083833e6109e381836135ef565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a84613611565b92610a2860405194856135ef565b848452602085840101116104d657506109ce92610a4b916020808501910161341c565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613478565b91610a87613ee1565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614739565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d95565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613ee1565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614739565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61475f565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d60026040892001613a2f565b6001600160801b03610c718160208401511692826040818351169201511690613663565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc38186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135ef565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135ef565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e9185614614565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb613462565b611003613478565b906064359067ffffffffffffffff82116106395736602383011215610639578160040135928461103285613611565b9361104060405195866135ef565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a82565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613d01565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a4613462565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135ef565b60405191829160208352602083019061343d565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613d01565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613ee1565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138ee565b956114cc60405197886135ef565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138ee565b9261150360405194856135ef565b808452601f19611512826138ee565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bf9565b51511664ffffffffff80602061154d85613bf9565b51015116860116604051916115618361359a565b8252602082015261157186613bf9565b5261157b85613bf9565b5060015b8281106116555750505061159584600401613a61565b906115a260248601613a61565b906115af6044870161398f565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a75565b948161160260a48c01613a75565b976040519d8e613569565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161393c565b610100820152613f3b565b604051908152f35b806001600160801b0361166a60019385613c06565b51511664ffffffffff8060206116835f1986018c613c06565b510151168160206116948689613c06565b510151160116604051916116a78361359a565b825260208201526116b88289613c06565b526116c38188613c06565b500161157f565b6020906040516116d98161359a565b5f81525f8382015282828901015201611515565b60206040916116fc3685613906565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d816135b6565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135d3565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c161515895201613a2f565b6101208c019081526118818a613d01565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c6135b6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611954906139bb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce9161350d565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134dc565b90611a96613ee1565b82915b808310611aa4578380f35b611aaf83828461396b565b3592611ab9613ee1565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613c1a565b908086526009602052611b5d60026040882001613a2f565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613663565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b85886148bd565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135ef565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a602052206139bb565b60405191829160208352602083019061350d565b50346104d65760203660031901126104d65760043590611e79613ee1565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613d01565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135ef565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d657612176613462565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f0613462565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613bc6565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d657600435906122876139a3565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d98361359a565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134dc565b9060243567ffffffffffffffff8111610639576123549036906004016134dc565b9261235d613ee1565b83810361276357845b818110612371578580f35b61237c81838661396b565b3561238882848761396b565b35875260036020526001600160a01b03604088205416906123b26123ad84898861396b565b61398f565b6123ba613ee1565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614739565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61475f565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c060026040892001613a2f565b6001600160801b036124e48160208401511692826040818351169201511690613663565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d20015416946125368186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135ef565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135ef565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061271284614614565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614686565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613d01565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613ee1565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c881614614565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b366134a2565b9060405192612a6b6020856135ef565b858452613a82565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613ee1565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613c1a565b90805f526009602052612b86600260405f2001613a2f565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613663565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b85886148bd565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135ef565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613ee1565b604051612e2081613569565b612e2c8260040161348e565b8152612e3a6024830161348e565b6020820152612e4b6044830161362d565b604082015260648201356001600160a01b0381168103612d51576060820152612e766084830161355c565b6080820152612e8760a4830161355c565b60a0820152612e9860c483016138dc565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138ee565b90612edc60405192836135ef565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e084015261010436910161393c565b6020604091612f2c3689613906565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f82366134a2565b91613697565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613d01565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613c1a565b90613663565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa613462565b60243561310681613bc6565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d51576020612258600435613641565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135ef565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f49064906000000000000000000000000000000000000000000000000000000006020931490811561338e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133f2575b81156133c8575b5083613387565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836133c1565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506133ba565b5f5b83811061342d5750505f910152565b818101518382015260200161341e565b906020916134568151809281855285808601910161341c565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b81811061352a5750505090565b825180516001600160801b0316855260209081015164ffffffffff16818601526040909401939092019160010161351d565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761358657604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761358657604052565b610180810190811067ffffffffffffffff82111761358657604052565b6060810190811067ffffffffffffffff82111761358657604052565b90601f8019910116810190811067ffffffffffffffff82111761358657604052565b67ffffffffffffffff811161358657601f01601f191660200190565b35906001600160801b0382168203612d5157565b61364a81613bc6565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161368357565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156138c957815f5260036020526001600160a01b0360405f2054161515806138c1575b806138a4575b613891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137dc575b6001600160a01b039350856137a5575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361378d57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6137c4825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561372c565b919290508061383a575b156137f35782829161371c565b828461380b57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613868575b806137e65750825f526005602052336001600160a01b0360405f205416146137e6565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613845565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c16156136cc565b5060016136c6565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135865760051b60200190565b9190826040910312612d515760405161391e8161359a565b602061393781839561392f8161362d565b8552016138dc565b910152565b9190826040910312612d51576040516139548161359a565b60208082946139628161348e565b84520135910152565b919081101561397b5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b604051906139b08261359a565b5f6020838281520152565b9081546139c7816138ee565b926139d560405194856135ef565b81845260208401905f5260205f205f915b8383106139f35750505050565b600160208192604051613a058161359a565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139e6565b90604051613a3c816135d3565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a8e838284613697565b803b613a9b575b50505050565b602091613ae16001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061343d565b03815f865af15f9181613b69575b50613b1d5750613afd61470a565b80519081613b185782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b5757505f808080613a95565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613bbe575b81613b85602093836135ef565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613aef565b3d9150613b78565b805f5260036020526001600160a01b0360405f205416908115613be7575090565b637e27328960e01b5f5260045260245ffd5b80511561397b5760200190565b805182101561397b5760209160051b010190565b9064ffffffffff421691805f52600a602052613c3860405f206139bb565b908364ffffffffff6020613c4b85613bf9565b5101511611613cfa57805f5260096020528364ffffffffff60405f205460c81c161115613cdb57506001600160801b03613c8482613bf9565b515116916001925b8251841015613cd4578464ffffffffff6020613ca88787613c06565b5101511611613cd4576001600160801b0360019181613cc78787613c06565b5151160116930192613c8c565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613d235750600490565b805f52600960205260405f205460f81c613d8f57805f52600960205264ffffffffff60405f205460a01c164210613d8a57613d5d81613c1a565b905f5260096020526001600160801b0380600260405f200154169116105f14613d8557600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ecf575b80613eb2575b613ea0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e69575b1680613e51575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613e0d565b613e88835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613e06565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613dba565b506001600160a01b0382161515613db4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613f1357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f5d6001600160801b03604084015116602061010085015101519061477f565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145ec5780156145c4578151801561459c577f00000000000000000000000000000000000000000000000000000000000000008111614571575064ffffffffff6020613fcb84613bf9565b5101511681101561452d57505f905f905f81515f905b8082106144a5575050505064ffffffffff804216911690818110156144775750506001600160801b03169081810361444957505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206141ad8751975f19890190613c06565b51015160c81b169360a01b169116171785555f5b818110614397575050600187016007556001600160a01b0360208301511680156138c9576141f7886001600160a01b0392613d95565b1661436b5786826142456001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061485c565b6001600160801b036020840151168061433b575b506001600160a01b03815116946143306143126001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142b78b61359a565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061350d565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614365906001600160a01b036060840151166001600160a01b03610100850151511690339061485c565b5f614259565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f20906143b28160e0870151613c06565b5182549268010000000000000000841015613586576001840180825584101561397b576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016141c1565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b91935091936144c9906001600160801b036144c08588613c06565b5151169061475f565b9364ffffffffff8060206144dd8685613c06565b510151169416808511156144f957506001849301909291613fe1565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061453e84613bf9565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561465a575b508115614641575090565b90506001600160a01b036146553392613641565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614636565b805f52600960205261469d600260405f2001613a2f565b90805f52600960205260ff600160405f20015460a01c165f146146cb5750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ed57506146ea90613c1a565b90565b6146ea91506001600160801b036040818351169201511690613663565b3d15614734573d9061471b82613611565b9161472960405193846135ef565b82523d5f602084013e565b606090565b6146ea9061474681614686565b905f526009602052600260405f20015460801c90613663565b906001600160801b03809116911601906001600160801b03821161368357565b91909160405161478e8161359a565b5f81525f6020820152926001600160801b03821690811561483f5767016345785d8a00008111614808576147ca6001600160801b03918361499b565b16602085019181835211156147f4576001600160801b0391826147ef92511690613663565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516148508161359a565b5f81525f602082015290565b9091926001600160a01b036148bb9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148b66084836135ef565b61490d565b565b6148bb926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148b66064836135ef565b5f806001600160a01b0361493693169360208151910182865af161492f61470a565b9083614a49565b8051908115159182614977575b505061494c5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614943565b9091905f1983820983820291828083109203918083039214614a3857670de0b6b3a7640000821015614a08577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a865750805115614a5e57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614acc575b614a97575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a8f56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601781527f4e6f6e2d416c7068616e756d657269632053796d626f6c000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; + hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 7535afac1..4b56a6c03 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -303,8 +303,8 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { } /// @notice Checks whether the provided string contains only alphanumeric characters and spaces. - /// @dev Note that this returns true for empty strings, but it is not a security concern. - function isAlphanumeric(string memory str) internal pure returns (bool) { + /// @dev Note that this returns true for empty strings. + function isAlphanumericWithSpaces(string memory str) internal pure returns (bool) { // Convert the string to bytes to iterate over its characters. bytes memory b = bytes(str); @@ -368,8 +368,8 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { if (bytes(symbol).length > 30) { return "Long Symbol"; } else { - if (!isAlphanumeric(symbol)) { - return "Non-Alphanumeric Symbol"; + if (!isAlphanumericWithSpaces(symbol)) { + return "Unsupported Symbol"; } return symbol; } diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol b/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol new file mode 100644 index 000000000..59fa92a11 --- /dev/null +++ b/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; + +contract IsAlphanumericWithSpaces_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { + function test_IsAlphanumericWithSpaces_EmptyString() external view { + string memory symbol = ""; + bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + } + + modifier whenNotEmptyString() { + _; + } + + function test_IsAlphanumericWithSpaces_ContainsUnsupportedCharacters() external view whenNotEmptyString { + string memory symbol = ""; + bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo/"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo\\"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo%"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo&"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo("; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo)"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo\""; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo'"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo`"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo;"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + + symbol = "foo%20"; // URL-encoded empty space + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertFalse(result, "isAlphanumericWithSpaces"); + } + + modifier whenOnlySupportedCharacters() { + _; + } + + function test_IsAlphanumericWithSpaces() external view whenNotEmptyString whenOnlySupportedCharacters { + string memory symbol = "foo"; + bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = "Foo"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = "Foo "; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = "Foo Bar"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = " "; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = "foo01234"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + + symbol = "123456789"; + result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertTrue(result, "isAlphanumericWithSpaces"); + } +} diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree b/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree similarity index 56% rename from test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree rename to test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree index c02ab1f10..4583ea755 100644 --- a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.tree +++ b/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree @@ -1,8 +1,8 @@ -isAlphanumeric.t.sol +isAlphanumericWithSpaces.t.sol ├── when the symbol is an empty string │ └── it should return true └── when the symbol is not an empty string - ├── given the symbol does not contain only alphanumeric characters + ├── given the symbol contain unsupported characters │ └── it should return false - └── given the symbol contains only alphanumeric characters + └── given the symbol contains only supported characters └── it should return true diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol b/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol deleted file mode 100644 index 7c24e44d5..000000000 --- a/test/integration/concrete/nft-descriptor/is-alphanumeric/isAlphanumeric.t.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; - -contract IsAlphanumeric_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { - function test_IsAlphanumeric_EmptyString() external view { - string memory symbol = ""; - bool result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - } - - modifier whenNotEmptyString() { - _; - } - - function test_IsAlphanumeric_ContainsNonAlphanumericCharacters() external view whenNotEmptyString { - string memory symbol = ""; - bool result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo/"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo\\"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo%"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo&"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo("; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo)"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo\""; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo'"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo`"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo;"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - - symbol = "foo%20"; // URL-encoded empty space - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertFalse(result, "isAlphanumeric"); - } - - modifier whenOnlyAlphanumericCharacters() { - _; - } - - function test_IsAlphanumeric() external view whenNotEmptyString whenOnlyAlphanumericCharacters { - string memory symbol = "foo"; - bool result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = "Foo"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = "Foo "; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = "Foo Bar"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = " "; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = "foo01234"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - - symbol = "123456789"; - result = nftDescriptorMock.isAlphanumeric_(symbol); - assertTrue(result, "isAlphanumeric"); - } -} diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index 7238f0a29..f2e1e9a10 100644 --- a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -51,7 +51,7 @@ contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_ function test_SafeAssetSymbol_NonAlphanumeric() external whenERC20Contract givenSymbolString givenSymbolNotLong { ERC20Mock asset = new ERC20Mock({ name: "Token", symbol: "" }); string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset)); - string memory expectedSymbol = "Non-Alphanumeric Symbol"; + string memory expectedSymbol = "Unsupported Symbol"; assertEq(actualSymbol, expectedSymbol, "symbol"); } diff --git a/test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol b/test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol similarity index 74% rename from test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol rename to test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol index e16a18529..4d5df33df 100644 --- a/test/integration/fuzz/nft-descriptor/isAlphanumeric.t.sol +++ b/test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract IsAlphanumeric_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { +contract IsAlphanumericWithSpaces_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { bytes1 internal constant SPACE = 0x20; // ASCII 32 bytes1 internal constant ZERO = 0x30; // ASCII 48 bytes1 internal constant NINE = 0x39; // ASCII 57 @@ -21,22 +21,22 @@ contract IsAlphanumeric_Integration_Fuzz_Test is NFTDescriptor_Integration_Share /// - String with only alphanumerical characters /// - String with only non-alphanumerical characters /// - String with both alphanumerical and non-alphanumerical characters - function testFuzz_IsAlphanumeric(string memory symbol) external view whenNotEmptyString { + function testFuzz_IsAlphanumericWithSpaces(string memory symbol) external view whenNotEmptyString { bytes memory b = bytes(symbol); uint256 length = b.length; bool expectedResult = true; for (uint256 i = 0; i < length; ++i) { bytes1 char = b[i]; - if (!isAlphanumericChar(char)) { + if (!isAlphanumericOrSpaceChar(char)) { expectedResult = false; break; } } - bool actualResult = nftDescriptorMock.isAlphanumeric_(symbol); - assertEq(actualResult, expectedResult, "isAlphanumeric"); + bool actualResult = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); + assertEq(actualResult, expectedResult, "isAlphanumericWithSpaces"); } - function isAlphanumericChar(bytes1 char) internal pure returns (bool) { + function isAlphanumericOrSpaceChar(bytes1 char) internal pure returns (bool) { bool isSpace = char == SPACE; bool isDigit = char >= ZERO && char <= NINE; bool isUppercaseLetter = char >= A && char <= Z; diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index a5b7176ae..f63eca0cf 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -78,8 +78,8 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { return SVGElements.hourglass(status); } - function isAlphanumeric_(string memory symbol) external pure returns (bool) { - return isAlphanumeric(symbol); + function isAlphanumericWithSpaces_(string memory symbol) external pure returns (bool) { + return isAlphanumericWithSpaces(symbol); } function mapSymbol_(IERC721Metadata nft) external view returns (string memory) { From 600b1bd3175880dfeab16a09948e4159556e357e Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 19 Jun 2024 14:48:37 +0300 Subject: [PATCH 120/132] docs: add ASCII art in NFT Descriptor (#950) --- src/SablierV2NFTDescriptor.sol | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index 4b56a6c03..a88661cc6 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -15,6 +15,24 @@ import { Errors } from "./libraries/Errors.sol"; import { NFTSVG } from "./libraries/NFTSVG.sol"; import { SVGElements } from "./libraries/SVGElements.sol"; +/* + +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ + +███╗ ██╗███████╗████████╗ ██████╗ ███████╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ +████╗ ██║██╔════╝╚══██╔══╝ ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ +██╔██╗ ██║█████╗ ██║ ██║ ██║█████╗ ███████╗██║ ██████╔╝██║██████╔╝ ██║ ██║ ██║██████╔╝ +██║╚██╗██║██╔══╝ ██║ ██║ ██║██╔══╝ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ██║ ██║██╔══██╗ +██║ ╚████║██║ ██║ ██████╔╝███████╗███████║╚██████╗██║ ██║██║██║ ██║ ╚██████╔╝██║ ██║ +╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ + +*/ + /// @title SablierV2NFTDescriptor /// @notice See the documentation in {ISablierV2NFTDescriptor}. contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { From abf7154d5371ab957b86fce9a8a4801499573d63 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 24 Jun 2024 23:07:01 +0300 Subject: [PATCH 121/132] feat: hook allowlist (#951) * refactor: delete sender withdraw hooks refactor: delete renounce hook test: improve test function names test: update renounce and withdraw hook tests * refactor: rename hooks * refactor: get rid of "hooks" directory * feat: add marker "IS_SABLIER_RECIPIENT" refactor: rename "SablierV2Recipient" to "SablierRecipient" * feat: hook allowlist feat: isAllowedToHook feat: allowToHook test: rename recipient hooks mocks * feat: check allowlist when running hooks refactor: remove try/ catch in hooks refactor: rename "_allowed" to "_allowedToHook" test: update cancel and withdraw tests * build: update precompiles * fix: remove stale dir in prepare-artifacts script * docs: update withdraw natspec * chore: address PR feedback * feat: include function selector in the return value of hook calls * fix: redundant dev notes, use interface selector * test: fix bugs * feat: replace IS_SABLIER_RECIPIENT with IERC165-supportsInterface * refactor: remove local import from Errors * docs: polish natspec * refactor: rename recipient interface * refactor: change param type to "address" * build: update precompiles * refactor: remove unneeded address casting * docs: polish natspec * chore: update count map in Base script * chore: update benchmarks * docs: mention allowlist contract in Security doc * docs: update wording --------- Co-authored-by: andreivladbrg Co-authored-by: smol-ninja --- SECURITY.md | 2 + benchmark/results/SablierV2LockupDynamic.md | 54 +-- benchmark/results/SablierV2LockupLinear.md | 30 +- benchmark/results/SablierV2LockupTranched.md | 54 +-- precompiles/Precompiles.sol | 13 +- script/Base.s.sol | 40 +-- script/DeployCore.s.sol | 8 +- script/DeployCore2.s.sol | 6 - script/DeployDeterministicCore.s.sol | 9 +- script/DeployDeterministicCore2.s.sol | 7 - script/DeployDeterministicLockupDynamic.s.sol | 1 - script/DeployDeterministicLockupLinear.s.sol | 1 - .../DeployDeterministicLockupTranched.s.sol | 1 - script/DeployDeterministicNFTDescriptor.s.sol | 1 - script/DeployLockupDynamic.s.sol | 1 - script/DeployLockupLinear.s.sol | 1 - script/DeployLockupTranched.s.sol | 1 - script/DeployNFTDescriptor.s.sol | 1 - shell/prepare-artifacts.sh | 6 +- src/SablierV2LockupDynamic.sol | 4 +- src/SablierV2LockupLinear.sol | 2 +- src/abstracts/SablierV2Lockup.sol | 80 +++-- src/interfaces/ISablierLockupRecipient.sol | 57 ++++ src/interfaces/ISablierV2Lockup.sol | 30 +- src/interfaces/hooks/ISablierV2Recipient.sol | 46 --- src/interfaces/hooks/ISablierV2Sender.sol | 19 -- src/libraries/Errors.sol | 9 + test/Base.t.sol | 12 +- test/integration/Integration.t.sol | 30 +- .../lockup-dynamic/LockupDynamic.t.sol | 32 +- .../concrete/lockup-linear/LockupLinear.t.sol | 32 +- .../lockup-tranched/LockupTranched.t.sol | 32 +- .../lockup/allow-to-hook/allowToHook.t.sol | 80 +++++ .../lockup/allow-to-hook/allowToHook.tree | 12 + .../concrete/lockup/cancel/cancel.t.sol | 145 ++++---- .../concrete/lockup/cancel/cancel.tree | 50 ++- .../is-allowed-to-hook/isAllowedToHook.t.sol | 29 ++ .../is-allowed-to-hook/isAllowedToHook.tree | 5 + .../concrete/lockup/renounce/renounce.t.sol | 119 +------ .../concrete/lockup/renounce/renounce.tree | 28 +- .../lockup/withdraw-hooks/withdrawHooks.t.sol | 237 ++++--------- .../lockup/withdraw-hooks/withdrawHooks.tree | 31 +- .../concrete/lockup/withdraw/withdraw.t.sol | 319 ++++++------------ .../concrete/lockup/withdraw/withdraw.tree | 171 ++++------ .../nft-descriptor/generateAccentColor.t.sol | 1 + .../fuzz/lockup-linear/streamedAmountOf.t.sol | 2 +- test/integration/fuzz/lockup/cancel.t.sol | 23 +- test/integration/shared/lockup/cancel.t.sol | 20 +- test/integration/shared/lockup/withdraw.t.sol | 25 +- test/mocks/Hooks.sol | 207 ++++++++++++ test/mocks/hooks/GoodRecipient.sol | 32 -- test/mocks/hooks/GoodSender.sol | 13 - test/mocks/hooks/ReentrantRecipient.sol | 34 -- test/mocks/hooks/ReentrantSender.sol | 15 - test/mocks/hooks/RevertingRecipient.sol | 35 -- test/mocks/hooks/RevertingSender.sol | 14 - test/utils/Events.sol | 2 + 57 files changed, 1104 insertions(+), 1167 deletions(-) create mode 100644 src/interfaces/ISablierLockupRecipient.sol delete mode 100644 src/interfaces/hooks/ISablierV2Recipient.sol delete mode 100644 src/interfaces/hooks/ISablierV2Sender.sol create mode 100644 test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol create mode 100644 test/integration/concrete/lockup/allow-to-hook/allowToHook.tree create mode 100644 test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol create mode 100644 test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree create mode 100644 test/mocks/Hooks.sol delete mode 100644 test/mocks/hooks/GoodRecipient.sol delete mode 100644 test/mocks/hooks/GoodSender.sol delete mode 100644 test/mocks/hooks/ReentrantRecipient.sol delete mode 100644 test/mocks/hooks/ReentrantSender.sol delete mode 100644 test/mocks/hooks/RevertingRecipient.sol delete mode 100644 test/mocks/hooks/RevertingSender.sol diff --git a/SECURITY.md b/SECURITY.md index 45fc4d2d8..dbf5eb603 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -55,6 +55,8 @@ vulnerability, it must adhere to these assumptions as well: 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). - There is no need for exponents greater than ~18.44 in `LockupDynamic` segments. +- Recipient contracts on the hook allowlist have gone through due diligence and are assumed to expose no risk to the + Sablier protocol. ### Rewards diff --git a/benchmark/results/SablierV2LockupDynamic.md b/benchmark/results/SablierV2LockupDynamic.md index c2d8538ab..de8e2145b 100644 --- a/benchmark/results/SablierV2LockupDynamic.md +++ b/benchmark/results/SablierV2LockupDynamic.md @@ -2,30 +2,30 @@ | Implementation | Gas Usage | | ---------------------------------------------------------- | --------- | -| `burn` | 15675 | -| `cancel` | 71687 | -| `renounce` | 40893 | -| `createWithDurations` (2 segments) (Broker fee set) | 198964 | -| `createWithDurations` (2 segments) (Broker fee not set) | 183487 | -| `createWithTimestamps` (2 segments) (Broker fee set) | 183160 | -| `createWithTimestamps` (2 segments) (Broker fee not set) | 178483 | -| `withdraw` (2 segments) (After End Time) (by Recipient) | 19001 | -| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27557 | -| `withdraw` (2 segments) (After End Time) (by Anyone) | 13904 | -| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27260 | -| `createWithDurations` (10 segments) (Broker fee set) | 390614 | -| `createWithDurations` (10 segments) (Broker fee not set) | 385944 | -| `createWithTimestamps` (10 segments) (Broker fee set) | 380649 | -| `createWithTimestamps` (10 segments) (Broker fee not set) | 375987 | -| `withdraw` (10 segments) (After End Time) (by Recipient) | 14188 | -| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32500 | -| `withdraw` (10 segments) (After End Time) (by Anyone) | 13911 | -| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32203 | -| `createWithDurations` (100 segments) (Broker fee set) | 2704451 | -| `createWithDurations` (100 segments) (Broker fee not set) | 2700745 | -| `createWithTimestamps` (100 segments) (Broker fee set) | 2606340 | -| `createWithTimestamps` (100 segments) (Broker fee not set) | 2602667 | -| `withdraw` (100 segments) (After End Time) (by Recipient) | 14188 | -| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88383 | -| `withdraw` (100 segments) (After End Time) (by Anyone) | 13891 | -| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88086 | +| `burn` | 15716 | +| `cancel` | 74341 | +| `renounce` | 39007 | +| `createWithDurations` (2 segments) (Broker fee set) | 200602 | +| `createWithDurations` (2 segments) (Broker fee not set) | 185037 | +| `createWithTimestamps` (2 segments) (Broker fee set) | 184780 | +| `createWithTimestamps` (2 segments) (Broker fee not set) | 180015 | +| `withdraw` (2 segments) (After End Time) (by Recipient) | 19108 | +| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27554 | +| `withdraw` (2 segments) (After End Time) (by Anyone) | 14239 | +| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27485 | +| `createWithDurations` (10 segments) (Broker fee set) | 395084 | +| `createWithDurations` (10 segments) (Broker fee not set) | 390326 | +| `createWithTimestamps` (10 segments) (Broker fee set) | 385125 | +| `createWithTimestamps` (10 segments) (Broker fee not set) | 380375 | +| `withdraw` (10 segments) (After End Time) (by Recipient) | 14295 | +| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32545 | +| `withdraw` (10 segments) (After End Time) (by Anyone) | 14246 | +| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32476 | +| `createWithDurations` (100 segments) (Broker fee set) | 2740781 | +| `createWithDurations` (100 segments) (Broker fee not set) | 2736987 | +| `createWithTimestamps` (100 segments) (Broker fee set) | 2642946 | +| `createWithTimestamps` (100 segments) (Broker fee not set) | 2639185 | +| `withdraw` (100 segments) (After End Time) (by Recipient) | 14295 | +| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88968 | +| `withdraw` (100 segments) (After End Time) (by Anyone) | 14226 | +| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88899 | diff --git a/benchmark/results/SablierV2LockupLinear.md b/benchmark/results/SablierV2LockupLinear.md index c1fe26028..d53fa08f9 100644 --- a/benchmark/results/SablierV2LockupLinear.md +++ b/benchmark/results/SablierV2LockupLinear.md @@ -2,18 +2,18 @@ | Implementation | Gas Usage | | ----------------------------------------------------------- | --------- | -| `burn` | 15669 | -| `cancel` | 54116 | -| `renounce` | 21338 | -| `createWithDurations` (Broker fee set) (cliff not set) | 127727 | -| `createWithDurations` (Broker fee not set) (cliff not set) | 112219 | -| `createWithDurations` (Broker fee set) (cliff set) | 136514 | -| `createWithDurations` (Broker fee not set) (cliff set) | 131804 | -| `createWithTimestamps` (Broker fee set) (cliff not set) | 113830 | -| `createWithTimestamps` (Broker fee not set) (cliff not set) | 109114 | -| `createWithTimestamps` (Broker fee set) (cliff set) | 136117 | -| `createWithTimestamps` (Broker fee not set) (cliff set) | 131403 | -| `withdraw` (After End Time) (by Recipient) | 29557 | -| `withdraw` (Before End Time) (by Recipient) | 19032 | -| `withdraw` (After End Time) (by Anyone) | 24460 | -| `withdraw` (Before End Time) (by Anyone) | 18735 | +| `burn` | 15694 | +| `cancel` | 56829 | +| `renounce` | 19381 | +| `createWithDurations` (Broker fee set) (cliff not set) | 129276 | +| `createWithDurations` (Broker fee not set) (cliff not set) | 113680 | +| `createWithDurations` (Broker fee set) (cliff set) | 138071 | +| `createWithDurations` (Broker fee not set) (cliff set) | 133273 | +| `createWithTimestamps` (Broker fee set) (cliff not set) | 115334 | +| `createWithTimestamps` (Broker fee not set) (cliff not set) | 110530 | +| `createWithTimestamps` (Broker fee set) (cliff set) | 137629 | +| `createWithTimestamps` (Broker fee not set) (cliff set) | 132827 | +| `withdraw` (After End Time) (by Recipient) | 29701 | +| `withdraw` (Before End Time) (by Recipient) | 19104 | +| `withdraw` (After End Time) (by Anyone) | 24799 | +| `withdraw` (Before End Time) (by Anyone) | 19002 | diff --git a/benchmark/results/SablierV2LockupTranched.md b/benchmark/results/SablierV2LockupTranched.md index e2f0d3d33..ec7ea9494 100644 --- a/benchmark/results/SablierV2LockupTranched.md +++ b/benchmark/results/SablierV2LockupTranched.md @@ -2,30 +2,30 @@ | Implementation | Gas Usage | | ---------------------------------------------------------- | --------- | -| `burn` | 15713 | -| `cancel` | 61537 | -| `renounce` | 28738 | -| `createWithDurations` (2 tranches) (Broker fee set) | 198066 | -| `createWithDurations` (2 tranches) (Broker fee not set) | 182587 | -| `createWithTimestamps` (2 tranches) (Broker fee set) | 187974 | -| `createWithTimestamps` (2 tranches) (Broker fee not set) | 182597 | -| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20204 | -| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 15009 | -| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15108 | -| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14712 | -| `createWithDurations` (10 tranches) (Broker fee set) | 385207 | -| `createWithDurations` (10 tranches) (Broker fee not set) | 380536 | -| `createWithTimestamps` (10 tranches) (Broker fee set) | 393650 | -| `createWithTimestamps` (10 tranches) (Broker fee not set) | 388386 | -| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17959 | -| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19892 | -| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17669 | -| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19595 | -| `createWithDurations` (100 tranches) (Broker fee set) | 2645968 | -| `createWithDurations` (100 tranches) (Broker fee not set) | 2641781 | -| `createWithTimestamps` (100 tranches) (Broker fee set) | 2712165 | -| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2708591 | -| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46850 | -| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 74985 | -| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46553 | -| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 74688 | +| `burn` | 15738 | +| `cancel` | 63994 | +| `renounce` | 26501 | +| `createWithDurations` (2 tranches) (Broker fee set) | 199536 | +| `createWithDurations` (2 tranches) (Broker fee not set) | 183969 | +| `createWithTimestamps` (2 tranches) (Broker fee set) | 189410 | +| `createWithTimestamps` (2 tranches) (Broker fee not set) | 183945 | +| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20100 | +| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 14797 | +| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15199 | +| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14695 | +| `createWithDurations` (10 tranches) (Broker fee set) | 388757 | +| `createWithDurations` (10 tranches) (Broker fee not set) | 383998 | +| `createWithTimestamps` (10 tranches) (Broker fee set) | 397102 | +| `createWithTimestamps` (10 tranches) (Broker fee not set) | 391750 | +| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17855 | +| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19616 | +| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17760 | +| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19514 | +| `createWithDurations` (100 tranches) (Broker fee set) | 2672918 | +| `createWithDurations` (100 tranches) (Broker fee not set) | 2668643 | +| `createWithTimestamps` (100 tranches) (Broker fee set) | 2738297 | +| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2734635 | +| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46746 | +| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 73989 | +| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46644 | +| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 73887 | diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 859be7ce4..bbfe99e4f 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,11 +26,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e4576159096060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a05260016007556154fb908161040e8239608051816137e5015260a051818181610bdd01526138af0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461274857508063027b67441461272657806306fdde0314612632578063081812fc14612614578063095ea7b31461250f5780631400ecec1461245e5780631c1cdd4c146123d55780631e99d569146123b857806323b872dd1461239f57806331df3d481461228c57806340e58ee514611f65578063425d30dd14611f1357806342842e0e14611ee957806342966c6814611d0c5780634426757014611ce55780634857501f14611c5b5780634869e12d14611c1f5780634cc55e1114611b2657806354c022921461187057806357404b12146117d85780636352211e146117a85780636d0cee75146117a857806370a082311461173d57806375829def146116cb5780637cad6cd1146115bf5780637de6b1db146113bf5780638659c27014611021578063894e9a0d14610cec5780638f69b99314610c515780639067b67714610c005780639188ec8414610bc557806395d89b4114610ab8578063a22cb46514610a02578063a80fc071146109af578063ad35efd41461093c578063b2564569146108ea578063b637b8651461088e578063b88d4fde14610800578063b8a3be66146107cb578063b971302a1461077b578063bc2be1be1461072a578063c156a11d14610605578063c87b56dd146104e9578063d4dbd20b14610496578063d511609f14610449578063d975dfed146103fc578063e985e9c5146103a9578063ea5ead191461037a578063eac8f5b814610327578063f590c176146102ca578063f851a440146102a45763fdd46d601461025a575f80fd5b346102a15760603660031901126102a1576102736128a6565b6044356001600160801b038116810361029d5761029a916102926137db565b6004356134a9565b80f35b8280fd5b80fd5b50346102a157806003193601126102a1576001600160a01b036020915416604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760016040826020946001600160a01b0394526009855220015416604051908152f35b50346102a15760403660031901126102a15761029a60043561039a6128a6565b6103a3826140b6565b916130ac565b50346102a15760403660031901126102a1576001600160a01b0360406103cd612890565b92826103d76128a6565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c1615610316576020610438836140b6565b6001600160801b0360405191168152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081602093600293526009845220015460801c604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760036040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760203660031901126102a15760043561050781613539565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa9081156105fa578291610577575b604051602080825281906105739082018561286b565b0390f35b90503d8083833e6105888183612a3d565b81019060208183031261029d5780519067ffffffffffffffff82116105f6570181601f8201121561029d578051926105bf84612a5f565b926105cd6040519485612a3d565b848452602085840101116102a15750610573926105f0916020808501910161284a565b5f61055d565b8380fd5b6040513d84823e3d90fd5b50346102a15760403660031901126102a157600435906106236128a6565b9161062c6137db565b808252600960205260ff600160408420015460a81c161561071857805f5260036020526001600160a01b0360405f205416928333036107005761066e826140b6565b6001600160801b0381166106ef575b506001600160a01b038116156106dc5761069f826001600160a01b039261368f565b16806106b85760248383637e27328960e01b8252600452fd5b908382036106c4578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b6106fa9085846130ac565b5f61067d565b63216caf0d60e01b8352600482905233602452604483fd5b6024925062b8e7e760e51b8252600452fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c1615610316576040816020936001600160a01b03935260098452205416604051908152f35b50346102a15760203660031901126102a15760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346102a15760803660031901126102a15761081a612890565b6108226128a6565b906064359067ffffffffffffffff82116105f657366023830112156105f6578160040135928461085185612a5f565b9361085f6040519586612a3d565b858552366024878301011161088a578561029a96602460209301838801378501015260443591612f68565b5080fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657604081610573936108d69352600a60205220612ee1565b60405191829160208352602083019061293b565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460b01c166040519015158152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610975906135fb565b60405190600581101561098a57602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760026040826020946001600160801b0394526009855220015416604051908152f35b50346102a15760403660031901126102a157610a1c612890565b6024359081151580920361029d576001600160a01b0316908115610a8c57338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346102a157806003193601126102a1576040519080600254908160011c91600181168015610bbb575b602084108114610ba757838652908115610b805750600114610b23575b61057384610b0f81860382612a3d565b60405191829160208352602083019061286b565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b808210610b6657509091508101602001610b0f82610aff565b919260018160209254838588010152019101909291610b4d565b60ff191660208087019190915292151560051b85019092019250610b0f9150839050610aff565b602483634e487b7160e01b81526022600452fd5b92607f1692610ae2565b50346102a157806003193601126102a15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c16156103165760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346102a15760203660031901126102a157600435805f52600960205260ff600160405f20015460a81c161561099e57610c8a906135fb565b9060058210159081610ccb5760028314918215610cdf575b8215610cb6575b6020836040519015158152f35b909150610ccb57506004602091145f80610ca9565b80634e487b7160e01b602492526021600452fd5b5060038314915080610ca2565b50346102a15760203660031901126102a15760043590604051610180810181811067ffffffffffffffff82111761100d576060916101609160405283815283602082015283604082015283838201528360808201528360a08201528360c08201528360e08201528361010082015283610120820152610d69612e91565b6101408201520152818152600960205260ff600160408320015460a81c161561031657815f52600960205260405f2060405190610da582612a20565b8054916001600160a01b0383168152602081019364ffffffffff8460a01c168552604082019264ffffffffff8560c81c168452606083019360ff8660f01c1615158552608084019560f81c1515865260018201549260a08501956001600160a01b038516875260c086019060ff8660a01c1615158252610e46600260e089019660ff8960a81c161515885260ff6101008b019960b01c161515895201612eaf565b61012088019081526002610e598d6135fb565b610e62816129ad565b14611005575b5197516001600160a01b0316935164ffffffffff1690511515915115159451151595511515968b5f52600360205260405f20546001600160a01b03169b8452600a6020526040842090516001600160a01b03169a5164ffffffffff169951151593506040519a610eda6101808d612a3d565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610f2e90612ee1565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105739161293b565b838252610e68565b602483634e487b7160e01b81526041600452fd5b50346102a15760203660031901126102a15760043567ffffffffffffffff811161088a5761105390369060040161290a565b9061105c6137db565b82915b80831061106a578380f35b611075838284612e20565b359261107f6137db565b835f52600960205260ff600160405f20015460a81c16156113ac578385526009602052604085206001015460a01c60ff16156110c85760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c61139a576110fd815f5260096020526001600160a01b0360405f205416331490565b156113845761110b8161356c565b90805f526009602052611123600260405f2001612eaf565b916001600160801b038351166001600160801b038216101561137157815f52600960205260ff60405f205460f01c161561135e579061117a826001600160801b036020818796818d99511603169501511690612ab1565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215611339575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506112966001600160a01b03600160405f200154169461126e8b8588614510565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6112da575b505050505050600101919061105f565b813b1561133557856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af161131d575b808080806112ca565b9061132791612a3d565b835f126105f657835f611314565b8580fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556111c4565b506339c6dc7360e21b8652600452602485fd5b506322cad1af60e11b8652600452602485fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b838562b8e7e760e51b8152602491600452fd5b50346102a15760203660031901126102a157600435906113dd6137db565b818152600960205260ff600160408320015460a81c161561031657611401826135fb565b61140a816129ad565b600481036114255750602491634a5541ef60e01b8252600452fd5b61142e816129ad565b60038103611449575060249163fe19f19f60e01b8252600452fd5b600290611455816129ad565b146115ad57611478825f5260096020526001600160a01b0360405f205416331490565b1561158e57818152600960205260ff604082205460f01c161561157c57818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a1805f5260036020526001600160a01b0360405f20541690813b61151e575050f35b813b156115785782916024839260405195869384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611565579050f35b61156e91612a3d565b805f126102a15780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b82526004526001600160a01b033316602452fd5b6024916322cad1af60e11b8252600452fd5b50346102a15760203660031901126102a1576004356001600160a01b03811680910361088a576001600160a01b0382541633810361169c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116885760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346102a15760203660031901126102a1576116e5612890565b9080546001600160a01b03811633810361169c57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346102a15760203660031901126102a1576001600160a01b0361175f612890565b16801561177c578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346102a15760203660031901126102a15760206117c7600435613539565b6001600160a01b0360405191168152f35b50346102a15760203660031901126102a157600435906117f6612e79565b50818152600960205260ff600160408320015460a81c1615610316579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c1682519161184883612a04565b8252602082015261186e8251809264ffffffffff60208092828151168552015116910152565bf35b50346102a15760203660031901126102a1576004359067ffffffffffffffff82116102a15781360361012060031982011261088a576118ad6137db565b60c4830135906022190181121561088a57820160048101359067ffffffffffffffff821161029d5760240190606081023603821361029d57906118f1913691612d54565b8051916118fd83612d3c565b9261190b6040519485612a3d565b808452601f1961191a82612d3c565b01825b818110611b0f57505064ffffffffff4216926001600160801b0361194082613835565b51511667ffffffffffffffff602061195784613835565b5101511664ffffffffff80604061196d86613835565b510151168701169060405192611982846129e8565b83526020830152604082015261199786613835565b526119a185613835565b5060015b828110611a7b575050506119bb84600401612e58565b906119c860248601612e58565b906119d560448701612e44565b6064870135916001600160a01b0383168093036102a1576020611a73611a33611a688b8b8b8b8b8b6001600160801b038c6001600160a01b03611a1a60848a01612e6c565b9481611a2860a48c01612e6c565b976040519d8e6129b7565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612df1565b610100820152613856565b604051908152f35b806001600160801b03611a9060019385613842565b51511667ffffffffffffffff6020611aa88487613842565b5101511664ffffffffff806040611ac25f1987018d613842565b51015116816040611ad3878a613842565b5101511601169060405192611ae7846129e8565b835260208301526040820152611afd8289613842565b52611b088188613842565b50016119a5565b602090611b1a612e91565b8282890101520161191d565b50346102a15760403660031901126102a15760043567ffffffffffffffff811161088a57611b5890369060040161290a565b9060243567ffffffffffffffff81116105f657611b7990369060040161290a565b611b816137db565b808403611bef57845b848110611b95578580f35b80611be9611ba66001938888612e20565b35611bb2838989612e20565b35895260036020526001600160a01b0360408a205416611bdb611bd685888a612e20565b612e44565b91611be46137db565b6134a9565b01611b8a565b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c161561031657602061043883614006565b50346102a15760203660031901126102a15760043590815f52600960205260ff600160405f20015460a81c16156103165780611c96836135fb565b926005841015611cd157600260209403611cb7575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f80611cab565b602482634e487b7160e01b81526021600452fd5b50346102a157806003193601126102a15760206001600160a01b0360085416604051908152f35b50346102a15760203660031901126102a157600435611d296137db565b808252600960205260ff600160408420015460a81c161561099e57808252600960205260ff600160408420015460a01c1615611ebe57611d6881613f94565b15611ea85780825260036020526001600160a01b03604083205416151580611ea1575b80611e84575b611e72577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b036040832054168015908115611e3b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611e29575080f35b637e27328960e01b8252600452602490fd5b611e5a835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f19019055611ddf565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c1615611d91565b5081611d8b565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346102a15761029a611efb366128d0565b9060405192611f0b602085612a3d565b858452612f68565b50346102a15760203660031901126102a15760043590818152600960205260ff600160408320015460a81c161561031657600160408260209460ff94526009855220015460a01c166040519015158152f35b50346121fa5760203660031901126121fa5760043590611f836137db565b815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c165f14611fcd5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c61226857612000815f5260096020526001600160a01b0360405f205416331490565b156122495761200e8161356c565b90805f526009602052612026600260405f2001612eaf565b916001600160801b038351166001600160801b038216101561223657815f52600960205260ff60405f205460f01c161561222357806001600160801b0360208161207a948188511603169501511690612ab1565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b038116919082156121fe575b815f526009602052600360405f20016001600160801b0385166fffffffffffffffffffffffffffffffff19825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061216e6001600160a01b03600160405f200154169461126e8b8588614510565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b6121a5578580f35b813b156121fa575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af16121e7575b808080808580f35b6121f391505f90612a3d565b5f806121df565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b198254161790556120c4565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa5760043567ffffffffffffffff81116121fa5761014060031982360301126121fa576122c66137db565b604051906122d3826129b7565b6122df816004016128bc565b82526122ed602482016128bc565b60208301526122fe60448201612a7b565b604083015260648101356001600160a01b03811681036121fa576060830152612329608482016129a0565b608083015261233a60a482016129a0565b60a083015261234b60c48201612d2a565b60c083015260e481013567ffffffffffffffff81116121fa57810191366023840112156121fa57611a68611a739261238f6020953690602460048201359101612d54565b60e0840152610104369101612df1565b346121fa576123b66123b0366128d0565b91612ae5565b005b346121fa575f3660031901126121fa576020600754604051908152f35b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d5761240d906135fb565b600581101561243957806020911590811561242e575b506040519015158152f35b600191501482612423565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b346121fa5760203660031901126121fa57600435805f52600960205260ff600160405f20015460a81c161561244d576020905f90805f526009835260ff60405f205460f01c16806124f3575b6124c1575b506001600160801b0360405191168152f35b6124ed9150805f52600983526124e76001600160801b03600260405f200154169161356c565b90612ab1565b826124af565b50805f526009835260ff600160405f20015460a01c16156124aa565b346121fa5760403660031901126121fa57612528612890565b60243561253481613539565b33151580612601575b806125ce575b6125a25781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612543565b50336001600160a01b038216141561253d565b346121fa5760203660031901126121fa5760206117c7600435612a8f565b346121fa575f3660031901126121fa576040515f6001548060011c9060018116801561271c575b602083108114612708578285529081156126e45750600114612686575b61057383610b0f81850382612a3d565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106126ca57509091508101602001610b0f612676565b9192600181602092548385880101520191019092916126b2565b60ff191660208086019190915291151560051b84019091019150610b0f9050612676565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612659565b346121fa575f3660031901126121fa57602060405167016345785d8a00008152f35b346121fa5760203660031901126121fa57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036121fa57817f4906490600000000000000000000000000000000000000000000000000000000602093149081156127bc575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612820575b81156127f6575b50836127b5565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836127ef565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506127e8565b5f5b83811061285b5750505f910152565b818101518382015260200161284c565b906020916128848151809281855285808601910161284a565b601f01601f1916010190565b600435906001600160a01b03821682036121fa57565b602435906001600160a01b03821682036121fa57565b35906001600160a01b03821682036121fa57565b60609060031901126121fa576004356001600160a01b03811681036121fa57906024356001600160a01b03811681036121fa579060443590565b9181601f840112156121fa5782359167ffffffffffffffff83116121fa576020808501948460051b0101116121fa57565b90602080835192838152019201905f5b8181106129585750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161294b565b359081151582036121fa57565b6005111561243957565b610120810190811067ffffffffffffffff8211176129d457604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176129d457604052565b6040810190811067ffffffffffffffff8211176129d457604052565b610140810190811067ffffffffffffffff8211176129d457604052565b90601f8019910116810190811067ffffffffffffffff8211176129d457604052565b67ffffffffffffffff81116129d457601f01601f191660200190565b35906001600160801b03821682036121fa57565b612a9881613539565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b038211612ad157565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b03168015612d1757815f5260036020526001600160a01b0360405f205416151580612d0f575b80612cf2575b612cdf577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2a575b6001600160a01b03935085612bf3575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612bdb57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c12825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b7a565b9192905080612c88575b15612c4157828291612b6a565b8284612c5957637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cb6575b80612c345750825f526005602052336001600160a01b0360405f20541614612c34565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c93565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615612b1a565b506001612b14565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff821682036121fa57565b67ffffffffffffffff81116129d45760051b60200190565b929192612d6082612d3c565b93612d6e6040519586612a3d565b60606020868581520193028201918183116121fa57925b828410612d925750505050565b6060848303126121fa5760405190612da9826129e8565b612db285612a7b565b825260208501359067ffffffffffffffff821682036121fa5782602092836060950152612de160408801612d2a565b6040820152815201930192612d85565b91908260409103126121fa57604051612e0981612a04565b6020808294612e17816128bc565b84520135910152565b9190811015612e305760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036121fa5790565b356001600160a01b03811681036121fa5790565b3580151581036121fa5790565b60405190612e8682612a04565b5f6020838281520152565b60405190612e9e826129e8565b5f6040838281528260208201520152565b90604051612ebc816129e8565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612eed81612d3c565b92612efb6040519485612a3d565b81845260208401905f5260205f205f915b838310612f195750505050565b600160208192604051612f2b816129e8565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f0c565b90612f74838284612ae5565b803b612f81575b50505050565b602091612fc76001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061286b565b03815f865af15f918161304f575b506130035750612fe3614087565b80519081612ffe5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361303d57505f808080612f7b565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116130a4575b8161306b60209383612a3d565b810103126121fa57517fffffffff00000000000000000000000000000000000000000000000000000000811681036121fa57905f612fd5565b3d915061305e565b9190916130b76137db565b805f52600960205260ff600160405f20015460a81c161561244d575f92815f52600960205260ff600160405f20015460a01c16613496576001600160a01b03811691821561346b576001600160801b038416801561343f57815f5260036020526001600160a01b0360405f20541690818514158061342f575b6133fb576001600160801b03613145846140b6565b168082116133c85750825f5260096020526001600160a01b0360405f20541694835f52600960205261318187600260405f20015460801c6140dc565b5f85815260096020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556131c490612eaf565b6001600160801b036131e88160208401511692826040818351169201511690612ab1565b161115613396575b835f526009602052837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160405f2001541694613239818a88614510565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1803314158061338c575b613324575b833314159081613319575b8161330e575b50613297575b5050505050565b823b1561330a57604051636fd110e960e01b815260048101919091523360248201526001600160a01b0390911660448201526001600160801b039092166064830152829082908183816084810103925af16132f5575b808080613290565b613300828092612a3d565b6102a157806132ed565b8480fd5b90508314155f61328a565b843b15159150613284565b803b156121fa57604051636fd110e960e01b8152600481018390523360248201526001600160a01b03841660448201526001600160801b03861660648201525f8160848183865af1613377575b50613279565b6133849196505f90612a3d565b5f945f613371565b50803b1515613274565b5f84815260096020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131f0565b90837fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b84837fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061343983613f94565b15613130565b507fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b9190915f92815f52600960205260ff600160405f20015460a81c161561227a57815f52600960205260ff600160405f20015460a01c16613496576001600160a01b03811691821561346b576001600160801b038416801561343f57815f5260036020526001600160a01b0360405f20541690818514158061342f576133fb576001600160801b03613145846140b6565b805f5260036020526001600160a01b0360405f20541690811561355a575090565b637e27328960e01b5f5260045260245ffd5b64ffffffffff4216815f5260096020528064ffffffffff60405f205460a01c1610156135f557815f52600960205264ffffffffff60405f205460c81c1611156135da57805f52600a602052600160405f2054115f146135d1576135ce906141bc565b90565b6135ce906140fc565b5f5260096020526001600160801b03600260405f2001541690565b50505f90565b805f52600960205260ff600160405f20015460a01c165f1461361d5750600490565b805f52600960205260405f205460f81c61368957805f52600960205264ffffffffff60405f205460a01c164210613684576136578161356c565b905f5260096020526001600160801b0380600260405f200154169116105f1461367f57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f2054161515806137c9575b806137ac575b61379a577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613763575b168061374b575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613707565b613782835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613700565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c16156136b4565b506001600160a01b03821615156136ae565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361380d57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e305760200190565b8051821015612e305760209160051b010190565b906138786001600160801b0360408401511660206101008501510151906143d2565b916001600160801b038351169060e08101519160c082019264ffffffffff8451168215613f6c578015613f445781518015613f1c577f00000000000000000000000000000000000000000000000000000000000000008111613ef1575064ffffffffff60406138e684613835565b51015116811015613ead57505f905f905f81515f905b808210613e25575050505064ffffffffff80421691169081811015613df75750506001600160801b031690818103613dc957505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613ad18751975f19890190613842565b51015160c81b169360a01b169116171785555f5b818110613cbb575050600187016007556001600160a01b036020830151168015612d1757613b1b886001600160a01b039261368f565b16613c8f578682613b696001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906144af565b6001600160801b0360208401511680613c5f575b506001600160a01b0381511694613c54613c366001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613bdb8b612a04565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061293b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613c89906001600160a01b036060840151166001600160a01b0361010085015151169033906144af565b5f613b7d565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f2090613cd68160e0870151613842565b518254680100000000000000008110156129d45760018101808555811015612e30576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613ae5565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613e49906001600160801b03613e408588613842565b515116906140dc565b9364ffffffffff806040613e5d8685613842565b51015116941680851115613e79575060018493019092916138fc565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613ebe84613835565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613fda575b508115613fc1575090565b90506001600160a01b03613fd53392612a8f565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613fb6565b805f52600960205261401d600260405f2001612eaf565b90805f52600960205260ff600160405f20015460a01c165f1461404b5750602001516001600160801b031690565b90815f52600960205260405f205460f81c61406a57506135ce9061356c565b6135ce91506001600160801b036040818351169201511690612ab1565b3d156140b1573d9061409882612a5f565b916140a66040519384612a3d565b82523d5f602084013e565b606090565b6135ce906140c381614006565b905f526009602052600260405f20015460801c90612ab1565b906001600160801b03809116911601906001600160801b038211612ad157565b5f818152600960205260409020546141339064ffffffffff60a082901c811660c89290921c81168290038116914282160316614560565b90805f52600a60205260405f20805415612e30575f5261418867ffffffffffffffff60205f205460801c1692825f5260096020526141836001600160801b03600260405f20015416948592614640565b6146b3565b9182136141a557506141a16001600160801b039161478e565b1690565b90505f526009602052600260405f20015460801c90565b9064ffffffffff421691805f52600960205260405f2090604051906141e082612a20565b61012061427360028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eaf565b92019182525f52600a60205261428b60405f20612ee1565b915f9264ffffffffff604061429f83613835565b510151168664ffffffffff5f925b1610614393578161432464ffffffffff9697988784816001600160801b036142dc614183986143299b9a613842565b5151169a8b9867ffffffffffffffff60206142f7868b613842565b51015116978260406143098784613842565b510151169480614376575050511680925b0316920316614560565b614640565b91821361434a5750906001600160801b03614344819361478e565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f14614371575090565b905090565b6040925090614388915f190190613842565b51015116809261431a565b936001600160801b03600191816143aa8886613842565b51511601169401958064ffffffffff8060406143c68b87613842565b510151169892986142ad565b9190916040516143e181612a04565b5f81525f6020820152926001600160801b0382169081156144925767016345785d8a0000811161445b5761441d6001600160801b0391836153b4565b1660208501918183521115614447576001600160801b03918261444292511690612ab1565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144a381612a04565b5f81525f602082015290565b9091926001600160a01b0361450e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614509608483612a3d565b6147c3565b565b61450e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614509606483612a3d565b600160ff1b81148015614633575b61460b575f81121561460257614592815f035b5f8412156145fb57835f0390614851565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116145cc575f19911813156145c75790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614851565b61459281614581565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b821461456e565b8061465a575061465657670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146146a5578061467d575050670de0b6b3a764000090565b670de0b6b3a764000081146146a15761469c906141836135ce93614957565b614aae565b5090565b5050670de0b6b3a764000090565b600160ff1b81148015614781575b614759575f811215614750576146e5815f035b5f84121561474957835f03906153b4565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471a575f19911813156145c75790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906153b4565b6146e5816146d4565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b5f81126147985790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b036147ec93169360208151910182865af16147e5614087565b9083615462565b805190811515918261482d575b50506148025750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126121fa57602001518015908115036121fa575f806147f9565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461491c57818410156148e257670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614929570490565b634e487b7160e01b5f52601260045260245ffd5b8015614929576ec097ce7bc90715b34b9f10000000000590565b805f811315614a8357670de0b6b3a76400008112614a6357506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614a5057506706f05b59d3b20000905b5f8213614a1a5750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614a42575b60011d90614a0d565b809192019160011d90614a39565b9050670de0b6b3a7640000929150020290565b5f1991508015614929576ec097ce7bc90715b34b9f100000000005614974565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614adb5768033dd1780914b9711419811261368457614ad2905f03614aae565b6135ce9061493d565b680a688906bd8affffff811361538957670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff000000000000008216615254575b670de0b6b3a76400009066ff0000000000008316615144575b65ff0000000000831661503c575b64ff000000008316614f3c575b63ff0000008316614e44575b62ff00008316614d54575b61ff008316614c6c575b60ff8316614b8c575b029060401c60bf031c90565b60808316614c59575b60408316614c46575b60208316614c33575b60108316614c20575b60088316614c0d575b60048316614bfa575b60028316614be7575b6001831615614b8057680100000000000000010260401c614b80565b680100000000000000010260401c614bcb565b680100000000000000030260401c614bc2565b680100000000000000060260401c614bb9565b6801000000000000000b0260401c614bb0565b680100000000000000160260401c614ba7565b6801000000000000002c0260401c614b9e565b680100000000000000590260401c614b95565b6180008316614d41575b6140008316614d2e575b6120008316614d1b575b6110008316614d08575b6108008316614cf5575b6104008316614ce2575b6102008316614ccf575b610100831615614b7757680100000000000000b10260401c614b77565b680100000000000001630260401c614cb2565b680100000000000002c60260401c614ca8565b6801000000000000058c0260401c614c9e565b68010000000000000b170260401c614c94565b6801000000000000162e0260401c614c8a565b68010000000000002c5d0260401c614c80565b680100000000000058b90260401c614c76565b628000008316614e31575b624000008316614e1e575b622000008316614e0b575b621000008316614df8575b620800008316614de5575b620400008316614dd2575b620200008316614dbf575b62010000831615614b6d576801000000000000b1720260401c614b6d565b680100000000000162e40260401c614da1565b6801000000000002c5c80260401c614d96565b68010000000000058b910260401c614d8b565b680100000000000b17210260401c614d80565b68010000000000162e430260401c614d75565b680100000000002c5c860260401c614d6a565b6801000000000058b90c0260401c614d5f565b63800000008316614f29575b63400000008316614f16575b63200000008316614f03575b63100000008316614ef0575b63080000008316614edd575b63040000008316614eca575b63020000008316614eb7575b6301000000831615614b625768010000000000b172180260401c614b62565b6801000000000162e4300260401c614e98565b68010000000002c5c8600260401c614e8c565b680100000000058b90c00260401c614e80565b6801000000000b17217f0260401c614e74565b680100000000162e42ff0260401c614e68565b6801000000002c5c85fe0260401c614e5c565b68010000000058b90bfc0260401c614e50565b6480000000008316615029575b6440000000008316615016575b6420000000008316615003575b6410000000008316614ff0575b6408000000008316614fdd575b6404000000008316614fca575b6402000000008316614fb7575b640100000000831615614b5657680100000000b17217f80260401c614b56565b68010000000162e42ff10260401c614f97565b680100000002c5c85fe30260401c614f8a565b6801000000058b90bfce0260401c614f7d565b68010000000b17217fbb0260401c614f70565b6801000000162e42fff00260401c614f63565b68010000002c5c8601cc0260401c614f56565b680100000058b90c0b490260401c614f49565b658000000000008316615131575b65400000000000831661511e575b65200000000000831661510b575b6510000000000083166150f8575b6508000000000083166150e5575b6504000000000083166150d2575b6502000000000083166150bf575b65010000000000831615614b49576801000000b1721835510260401c614b49565b680100000162e430e5a20260401c61509e565b6801000002c5c863b73f0260401c615090565b68010000058b90cf1e6e0260401c615082565b680100000b1721bcfc9a0260401c615074565b68010000162e43f4f8310260401c615066565b680100002c5c89d5ec6d0260401c615058565b6801000058b91b5bc9ae0260401c61504a565b66800000000000008316615241575b6640000000000000831661522e575b6620000000000000831661521b575b66100000000000008316615208575b660800000000000083166151f5575b660400000000000083166151e2575b660200000000000083166151cf575b6601000000000000831615614b3b5768010000b17255775c040260401c614b3b565b6801000162e525ee05470260401c6151ad565b68010002c5cc37da94920260401c61519e565b680100058ba01fb9f96d0260401c61518f565b6801000b175effdc76ba0260401c615180565b680100162f3904051fa10260401c615171565b6801002c605e2e8cec500260401c615162565b68010058c86da1c09ea20260401c615153565b678000000000000000821661536a575b670de0b6b3a7640000906740000000000000008316615357575b6720000000000000008316615344575b6710000000000000008316615331575b670800000000000000831661531e575b670400000000000000831661530b575b67020000000000000083166152f8575b67010000000000000083166152e5575b9050614b22565b680100b1afa5abcbed610260401c6152de565b68010163da9fb33356d80260401c6152ce565b680102c9a3e778060ee70260401c6152be565b6801059b0d31585743ae0260401c6152ae565b68010b5586cf9890f62a0260401c61529e565b6801172b83c7d517adce0260401c61528e565b6801306fe0a31b7152df0260401c61527e565b5077b504f333f9de648480000000000000000000000000000000615264565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461545157670de0b6b3a7640000821015615421577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061549f575080511561547757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806154e5575b6154b0575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156154a856fea164736f6c634300081a000a"; + hex"60c0604052346103e457615a426060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615634908161040e823960805181613927015260a051818181610bbf01526139f10152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127be57508063027b67441461279c57806306fdde03146126e1578063081812fc146126c3578063095ea7b3146125be5780631400ecec1461250d5780631c1cdd4c146124a95780631e99d5691461248c57806323b872dd14612475578063303acc851461243857806331df3d4814612325578063406887cb146121b357806340e58ee514611e9a578063425d30dd14611e4a57806342842e0e14611e2157806342966c6814611c5d5780634426757014611c375780634857501f14611bc65780634869e12d14611b8c5780634cc55e1114611a9457806354c02292146117e357806357404b12146117555780636352211e146117265780636d0cee751461172657806370a08231146116bc57806375829def1461164e5780637cad6cd11461155d5780637de6b1db146113de5780638659c27014610fe0578063894e9a0d14610cb15780638f69b99314610c315780639067b67714610be25780639188ec8414610ba857806395d89b4114610aa0578063a22cb465146109ec578063a80fc0711461099b578063ad35efd41461093c578063b2564569146108ec578063b637b86514610893578063b88d4fde1461080b578063b8a3be66146107d6578063b971302a14610788578063bc2be1be14610739578063c156a11d14610609578063c87b56dd146104f3578063d4dbd20b146104a2578063d511609f14610457578063d975dfed1461040c578063e985e9c5146103b3578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128eb565b6044356001600160801b03811681036102b0576102ae916102a661391d565b6004356133d1565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b0576102ae6004356103a46128eb565b6103ad826141f8565b91613062565b346102b05760403660031901126102b0576103cc6128d5565b6001600160a01b036103dc6128eb565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576104466020916141f8565b6001600160801b0360405191168152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b0576004356105108161369f565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156105fe575f90610581575b61057d906040519182916020835260208301906128b0565b0390f35b503d805f833e6105918183612a6e565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105c983612a90565b916105d76040519384612a6e565b838352602084830101116102b05761057d926105f9916020808501910161288f565b610565565b6040513d5f823e3d90fd5b346102b05760403660031901126102b0576004356106256128eb565b9061062e61391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f5260036020526001600160a01b0360405f2054169182330361071957610670826141f8565b6001600160801b038116610708575b506001600160a01b038116156106f5576106a1826001600160a01b03926137e3565b1691826106bb5750637e27328960e01b5f5260045260245ffd5b8083036106c457005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610713908484613062565b8361067f565b5063216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108246128d5565b61082c6128eb565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161085983612a90565b926108676040519485612a6e565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b60205261057d6108d860405f20612eeb565b604051918291602083526020830190612980565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576109749061374f565b6040516005821015610987576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a056128d5565b602435908115158092036102b0576001600160a01b0316908115610a7457335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610b9e575b602083108114610b8a57828552908115610b665750600114610b08575b61057d83610af481850382612a6e565b6040519182916020835260208301906128b0565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b4c57509091508101602001610af4610ae4565b919260018160209254838588010152019101909291610b34565b60ff191660208086019190915291151560051b84019091019150610af49050610ae4565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ac7565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c699061374f565b6005811015806109875760028214908115610ca5575b8115610c93575b6020826040519015158152f35b90506109875760046020911482610c86565b5050600381145f610c7f565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fcc57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d2c612e9b565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d6781612a51565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e06600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612eb9565b61012083019081526002610e198c61374f565b610e22816129f2565b14610fc4575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610e996101808d612a6e565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610eed90612eeb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057d91612980565b5f8752610e28565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101190369060040161294f565b9061101a61391d565b5f915b80831061102657005b611031838284612e2a565b359261103b61391d565b835f52600a60205260ff600160405f20015460a81c16156113cb57835f52600a60205260ff600160405f20015460a01c165f146110855783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113b9576110ba815f52600a6020526001600160a01b0360405f205416331490565b156113a3576110c8816136c0565b90805f52600a6020526110e0600260405f2001612eb9565b916001600160801b038351166001600160801b038216101561138f57815f52600a60205260ff60405f205460f01c161561137b57806001600160801b03602081611134948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611356575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061124f6001600160a01b03600160405f2001541694611227888588614652565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff611299866001600160a01b03165f52600960205260405f2090565b54166112af575b5050505050600101919061101d565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91611328575b50160361130c57808080806112a0565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611349915060203d811161134f575b6113418183612a6e565b81019061367f565b876112fc565b503d611337565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561117e565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b0576004356113fa61391d565b805f52600a60205260ff600160405f20015460a81c16156103235761141e8161374f565b611427816129f2565b600481036114425750634a5541ef60e01b5f5260045260245ffd5b61144b816129f2565b60038103611466575063fe19f19f60e01b5f5260045260245ffd5b600290611472816129f2565b1461154b57611495815f52600a6020526001600160a01b0360405f205416331490565b1561152c57805f52600a60205260ff60405f205460f01c161561151a576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611638575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116245760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116676128d5565b5f546001600160a01b03811633810361163857506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116dd6128d5565b1680156116fa575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174460043561369f565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b057600435611771612e83565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117bb83612a35565b825260208201526117e18251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761181e61391d565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b057611860913691612d46565b9081519161186d83612d2e565b9261187b6040519485612a6e565b808452601f1961188a82612d2e565b015f5b818110611a7d57505064ffffffffff4216916001600160801b036118b082613977565b51511667ffffffffffffffff60206118c784613977565b5101511664ffffffffff8060406118dd86613977565b5101511686011690604051926118f284612a19565b83526020830152604082015261190786613977565b5261191185613977565b5060015b8281106119e95750505061192b82600401612e62565b9261193860248401612e62565b9261194560448201612e4e565b916064820135936001600160a01b0385168095036102b0576020966119e1966119a1966001600160801b036119d6976001600160a01b0361198860848a01612e76565b948161199660a48c01612e76565b976040519d8e6129fc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612de3565b610100820152613998565b604051908152f35b806001600160801b036119fe60019385613984565b51511667ffffffffffffffff6020611a168487613984565b5101511664ffffffffff806040611a305f1987018d613984565b51015116816040611a41878a613984565b5101511601169060405192611a5584612a19565b835260208301526040820152611a6b8289613984565b52611a768188613984565b5001611915565b602090611a88612e9b565b8282890101520161188d565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ac590369060040161294f565b9060243567ffffffffffffffff81116102b057611ae690369060040161294f565b9091611af061391d565b818403611b5c575f5b848110611b0257005b80611b56611b136001938886612e2a565b35611b1f838987612e2a565b355f5260036020526001600160a01b0360405f205416611b48611b4385898b612e2a565b612e4e565b91611b5161391d565b6133d1565b01611af9565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610446602091614148565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611bff8261374f565b600581101561098757600203611c1d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c10565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c7961391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611df657611cb8816140d6565b156113a357805f5260036020526001600160a01b0360405f205416151580611def575b80611dd2575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d89575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d7757005b637e27328960e01b5f5260045260245ffd5b611da8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d2f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611ce1565b505f611cdb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3236612915565b9060405192611e42602085612a6e565b5f8452612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611eb661391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611eff57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113b957611f31815f52600a6020526001600160a01b0360405f205416331490565b1561152c57611f3f816136c0565b90805f52600a602052611f57600260405f2001612eb9565b916001600160801b038351166001600160801b03821610156121a057815f52600a60205260ff60405f205460f01c161561218d57806001600160801b03602081611fab948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612168575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061209e6001600160a01b03600160405f2001541694611227888588614652565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120e157005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91612149575b50160361213757005b632187e5e760e21b5f5260045260245ffd5b612162915060203d60201161134f576113418183612a6e565b8461212e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611ff5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121cc6128d5565b6001600160a01b035f54169033820361230e57806001600160a01b03913b156122e257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156105fe575f916122b3575b5015612288576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122d5915060203d6020116122db575b6122cd8183612a6e565b810190612e12565b8261223a565b503d6122c3565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761235f61391d565b6040519061236c826129fc565b61237881600401612901565b825261238660248201612901565b602083015261239760448201612aac565b604083015260648101356001600160a01b03811681036102b05760608301526123c2608482016129e5565b60808301526123d360a482016129e5565b60a08301526123e460c48201612d1c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119d66119e1926124286020953690602460048201359101612d46565b60e0840152610104369101612de3565b346102b05760203660031901126102b0576001600160a01b036124596128d5565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248636612915565b91612b02565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e19061374f565b6005811015610987578060209115908115612502575b506040519015158152f35b6001915014826124f7565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125a2575b612570575b506001600160801b0360405191168152f35b61259c9150805f52600a83526125966001600160801b03600260405f20015416916136c0565b90612ae2565b8261255e565b50805f52600a835260ff600160405f20015460a01c1615612559565b346102b05760403660031901126102b0576125d76128d5565b6024356125e38161369f565b331515806126b0575b8061267d575b6126515781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125f2565b50336001600160a01b03821614156125ec565b346102b05760203660031901126102b0576020611744600435612ac0565b346102b0575f3660031901126102b0576040515f6001548060011c90600181168015612792575b602083108114610b8a57828552908115610b6657506001146127345761057d83610af481850382612a6e565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061277857509091508101602001610af4610ae4565b919260018160209254838588010152019101909291612760565b91607f1691612708565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f49064906000000000000000000000000000000000000000000000000000000006020931490811561281a575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612865575b8115612854575b5083612813565b6301ffc9a760e01b9150148361284d565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612846565b5f5b8381106128a05750505f910152565b8181015183820152602001612891565b906020916128c98151809281855285808601910161288f565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b81811061299d5750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612990565b359081151582036102b057565b6005111561098757565b610120810190811067ffffffffffffffff821117610fcc57604052565b6060810190811067ffffffffffffffff821117610fcc57604052565b6040810190811067ffffffffffffffff821117610fcc57604052565b610140810190811067ffffffffffffffff821117610fcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610fcc57604052565b67ffffffffffffffff8111610fcc57601f01601f191660200190565b35906001600160801b03821682036102b057565b612ac98161369f565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162457565b91906001600160a01b031680156106f557815f5260036020526001600160a01b0360405f205416151580612d14575b80612cf7575b612ce4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2f575b6001600160a01b03935085612bf8575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036106c457505050565b612c17825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b97565b9192905080612c8d575b15612c4657828291612b87565b8284612c5e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cbb575b80612c395750825f526005602052336001600160a01b0360405f20541614612c39565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c98565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b37565b506001612b31565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fcc5760051b60200190565b929192612d5282612d2e565b93612d606040519586612a6e565b60606020868581520193028201918183116102b057925b828410612d845750505050565b6060848303126102b05760405190612d9b82612a19565b612da485612aac565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612dd360408801612d1c565b6040820152815201930192612d77565b91908260409103126102b057604051612dfb81612a35565b6020808294612e0981612901565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e3a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612e9082612a35565b5f6020838281520152565b60405190612ea882612a19565b5f6040838281528260208201520152565b90604051612ec681612a19565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612ef781612d2e565b92612f056040519485612a6e565b81845260208401905f5260205f205f915b838310612f235750505050565b600160208192604051612f3581612a19565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f16565b90612f7e838284612b02565b803b612f8b575b50505050565b602091612fd16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b0565b03815f865af15f9181613041575b5061300d5750612fed6141c9565b805190816130085782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361302f57505f808080612f85565b633250574960e11b5f5260045260245ffd5b61305b91925060203d60201161134f576113418183612a6e565b905f612fdf565b9061306b61391d565b815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f205416948583141580613344575b613310576001600160801b036130f7866141f8565b168085116132dd575061311c90855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561315f90612eb9565b6001600160801b036131838160208401511692826040818351169201511690612ae2565b1611156132ab575b835f52600a6020526131af836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613295575b6132195750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f91613276575b50160361213757808080612f85565b61328f915060203d60201161134f576113418183612a6e565b5f613267565b50835f52600960205260ff60405f20541661320f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561318b565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061334e856140d6565b156130e2565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f20541694858314158061366f575b613310576001600160801b0361345e866141f8565b168085116132dd575061348390855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134c690612eb9565b6001600160801b036134ea8160208401511692826040818351169201511690612ae2565b16111561363d575b835f52600a602052613516836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613618575b6135805750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f916135f9575b5016036135dd57808080612f85565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613612915060203d60201161134f576113418183612a6e565b5f6135ce565b5060ff613636856001600160a01b03165f52600960205260405f2090565b5416613576565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556134f2565b50613679856140d6565b15613449565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d77575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561374957815f52600a60205264ffffffffff60405f205460c81c16111561372e57805f52600b602052600160405f2054115f1461372557613722906142fe565b90565b6137229061423e565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137715750600490565b805f52600a60205260405f205460f81c6137dd57805f52600a60205264ffffffffff60405f205460a01c1642106137d8576137ab816136c0565b905f52600a6020526001600160801b0380600260405f200154169116105f146137d357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061390b575b806138ee575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138b7575b168061389f575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561385b565b6138d6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613854565b50805f52600a60205260ff600160405f20015460b01c1615613808565b506001600160a01b0382161515613802565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361394f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e3a5760200190565b8051821015612e3a5760209160051b010190565b906139ba6001600160801b036040840151166020610100850151015190614514565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140ae578015614086578151801561405e577f00000000000000000000000000000000000000000000000000000000000000008111614033575064ffffffffff6040613a2884613977565b51015116811015613fef57505f905f905f81515f905b808210613f67575050505064ffffffffff80421691169081811015613f395750506001600160801b031690818103613f0b57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c138751975f19890190613984565b51015160c81b169360a01b169116171785555f5b818110613dfd575050600187016007556001600160a01b0360208301511680156106f557613c5d886001600160a01b03926137e3565b16613dd1578682613cab6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145f1565b6001600160801b0360208401511680613da1575b506001600160a01b0381511694613d96613d786001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d1d8b612a35565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612980565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dcb906001600160a01b036060840151166001600160a01b0361010085015151169033906145f1565b5f613cbf565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e188160e0870151613984565b51825468010000000000000000811015610fcc5760018101808555811015612e3a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c27565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f8b906001600160801b03613f828588613984565b5151169061421e565b9364ffffffffff806040613f9f8685613984565b51015116941680851115613fbb57506001849301909291613a3e565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400084613977565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561411c575b508115614103575090565b90506001600160a01b036141173392612ac0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f8565b805f52600a60205261415f600260405f2001612eb9565b90805f52600a60205260ff600160405f20015460a01c165f1461418d5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ac5750613722906136c0565b61372291506001600160801b036040818351169201511690612ae2565b3d156141f3573d906141da82612a90565b916141e86040519384612a6e565b82523d5f602084013e565b606090565b6137229061420581614148565b905f52600a602052600260405f20015460801c90612ae2565b906001600160801b03809116911601906001600160801b03821161162457565b5f818152600a60205260409020546142759064ffffffffff60a082901c811660c89290921c811682900381169142821603166146a2565b90805f52600b60205260405f20805415612e3a575f526142ca67ffffffffffffffff60205f205460801c1692825f52600a6020526142c56001600160801b03600260405f20015416948592614782565b6147f5565b9182136142e757506142e36001600160801b03916148d0565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061432282612a51565b6101206143b560028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eb9565b92019182525f52600b6020526143cd60405f20612eeb565b915f9264ffffffffff60406143e183613977565b510151168664ffffffffff5f925b16106144d5578161446664ffffffffff9697988784816001600160801b0361441e6142c59861446b9b9a613984565b5151169a8b9867ffffffffffffffff6020614439868b613984565b510151169782604061444b8784613984565b5101511694806144b8575050511680925b03169203166146a2565b614782565b91821361448c5750906001600160801b0361448681936148d0565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b3575090565b905090565b60409250906144ca915f190190613984565b51015116809261445c565b936001600160801b03600191816144ec8886613984565b51511601169401958064ffffffffff8060406145088b87613984565b510151169892986143ef565b91909160405161452381612a35565b5f81525f6020820152926001600160801b0382169081156145d45767016345785d8a0000811161459d5761455f6001600160801b0391836154ed565b1660208501918183521115614589576001600160801b03918261458492511690612ae2565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e581612a35565b5f81525f602082015290565b9091926001600160a01b036146509481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261464b608483612a6e565b614905565b565b614650926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261464b606483612a6e565b600160ff1b81148015614775575b61474d575f811215614744576146d4815f035b5f84121561473d57835f039061498a565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470e575f19911813156147095790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061498a565b6146d4816146c3565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146b0565b8061479c575061479857670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e757806147bf575050670de0b6b3a764000090565b670de0b6b3a764000081146147e3576147de906142c561372293614a90565b614be7565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c3575b61489b575f81121561489257614827815f035b5f84121561488b57835f03906154ed565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485c575f19911813156147095790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ed565b61482781614816565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614803565b5f81126148da5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492e93169360208151910182865af16149276141c9565b908361559b565b805190811515918261496f575b50506149445750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149829250602080918301019101612e12565b155f8061493b565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a555781841015614a1b57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a62570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a62576ec097ce7bc90715b34b9f10000000000590565b805f811315614bbc57670de0b6b3a76400008112614b9c57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8957506706f05b59d3b20000905b5f8213614b535750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b7b575b60011d90614b46565b809192019160011d90614b72565b9050670de0b6b3a7640000929150020290565b5f1991508015614a62576ec097ce7bc90715b34b9f100000000005614aad565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c145768033dd1780914b971141981126137d857614c0b905f03614be7565b61372290614a76565b680a688906bd8affffff81136154c257670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538d575b670de0b6b3a76400009066ff000000000000831661527d575b65ff00000000008316615175575b64ff000000008316615075575b63ff0000008316614f7d575b62ff00008316614e8d575b61ff008316614da5575b60ff8316614cc5575b029060401c60bf031c90565b60808316614d92575b60408316614d7f575b60208316614d6c575b60108316614d59575b60088316614d46575b60048316614d33575b60028316614d20575b6001831615614cb957680100000000000000010260401c614cb9565b680100000000000000010260401c614d04565b680100000000000000030260401c614cfb565b680100000000000000060260401c614cf2565b6801000000000000000b0260401c614ce9565b680100000000000000160260401c614ce0565b6801000000000000002c0260401c614cd7565b680100000000000000590260401c614cce565b6180008316614e7a575b6140008316614e67575b6120008316614e54575b6110008316614e41575b6108008316614e2e575b6104008316614e1b575b6102008316614e08575b610100831615614cb057680100000000000000b10260401c614cb0565b680100000000000001630260401c614deb565b680100000000000002c60260401c614de1565b6801000000000000058c0260401c614dd7565b68010000000000000b170260401c614dcd565b6801000000000000162e0260401c614dc3565b68010000000000002c5d0260401c614db9565b680100000000000058b90260401c614daf565b628000008316614f6a575b624000008316614f57575b622000008316614f44575b621000008316614f31575b620800008316614f1e575b620400008316614f0b575b620200008316614ef8575b62010000831615614ca6576801000000000000b1720260401c614ca6565b680100000000000162e40260401c614eda565b6801000000000002c5c80260401c614ecf565b68010000000000058b910260401c614ec4565b680100000000000b17210260401c614eb9565b68010000000000162e430260401c614eae565b680100000000002c5c860260401c614ea3565b6801000000000058b90c0260401c614e98565b63800000008316615062575b6340000000831661504f575b6320000000831661503c575b63100000008316615029575b63080000008316615016575b63040000008316615003575b63020000008316614ff0575b6301000000831615614c9b5768010000000000b172180260401c614c9b565b6801000000000162e4300260401c614fd1565b68010000000002c5c8600260401c614fc5565b680100000000058b90c00260401c614fb9565b6801000000000b17217f0260401c614fad565b680100000000162e42ff0260401c614fa1565b6801000000002c5c85fe0260401c614f95565b68010000000058b90bfc0260401c614f89565b6480000000008316615162575b644000000000831661514f575b642000000000831661513c575b6410000000008316615129575b6408000000008316615116575b6404000000008316615103575b64020000000083166150f0575b640100000000831615614c8f57680100000000b17217f80260401c614c8f565b68010000000162e42ff10260401c6150d0565b680100000002c5c85fe30260401c6150c3565b6801000000058b90bfce0260401c6150b6565b68010000000b17217fbb0260401c6150a9565b6801000000162e42fff00260401c61509c565b68010000002c5c8601cc0260401c61508f565b680100000058b90c0b490260401c615082565b65800000000000831661526a575b654000000000008316615257575b652000000000008316615244575b651000000000008316615231575b65080000000000831661521e575b65040000000000831661520b575b6502000000000083166151f8575b65010000000000831615614c82576801000000b1721835510260401c614c82565b680100000162e430e5a20260401c6151d7565b6801000002c5c863b73f0260401c6151c9565b68010000058b90cf1e6e0260401c6151bb565b680100000b1721bcfc9a0260401c6151ad565b68010000162e43f4f8310260401c61519f565b680100002c5c89d5ec6d0260401c615191565b6801000058b91b5bc9ae0260401c615183565b6680000000000000831661537a575b66400000000000008316615367575b66200000000000008316615354575b66100000000000008316615341575b6608000000000000831661532e575b6604000000000000831661531b575b66020000000000008316615308575b6601000000000000831615614c745768010000b17255775c040260401c614c74565b6801000162e525ee05470260401c6152e6565b68010002c5cc37da94920260401c6152d7565b680100058ba01fb9f96d0260401c6152c8565b6801000b175effdc76ba0260401c6152b9565b680100162f3904051fa10260401c6152aa565b6801002c605e2e8cec500260401c61529b565b68010058c86da1c09ea20260401c61528c565b67800000000000000082166154a3575b670de0b6b3a7640000906740000000000000008316615490575b672000000000000000831661547d575b671000000000000000831661546a575b6708000000000000008316615457575b6704000000000000008316615444575b6702000000000000008316615431575b670100000000000000831661541e575b9050614c5b565b680100b1afa5abcbed610260401c615417565b68010163da9fb33356d80260401c615407565b680102c9a3e778060ee70260401c6153f7565b6801059b0d31585743ae0260401c6153e7565b68010b5586cf9890f62a0260401c6153d7565b6801172b83c7d517adce0260401c6153c7565b6801306fe0a31b7152df0260401c6153b7565b5077b504f333f9de64848000000000000000000000000000000061539d565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558a57670de0b6b3a764000082101561555a577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d857508051156155b057805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561e575b6155e9575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155e156fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614b786040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478f90816103e9823960805181613ada0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461309f57508063027b67441461307d57806306fdde0314612f89578063081812fc14612f6b578063095ea7b314612e665780631400ecec14612db55780631c1cdd4c14612d2c5780631e99d56914612d0f57806323b872dd14612cf657806340e58ee5146129e1578063425d30dd1461298f57806342842e0e1461296557806342966c681461278857806344267570146127615780634857501f146126eb5780634869e12d146126af5780634cc55e11146121f657806353b15727146120c857806357404b121461200d5780636352211e14611fdd5780636d0cee7514611fdd57806370a0823114611f7257806375829def14611f00578063780a82c814611eb25780637cad6cd114611da65780637de6b1db14611bb15780638659c2701461180d578063894e9a0d1461150b5780638f69b993146114705780639067b6771461141f57806395d89b4114611312578063a22cb4651461125c578063a80fc07114611209578063ab167ccc1461108c578063ad35efd414611019578063b256456914610fc7578063b88d4fde14610f36578063b8a3be6614610f01578063b971302a14610eb1578063bc2be1be14610e60578063c156a11d146109a8578063c87b56dd14610888578063d4dbd20b14610835578063d511609f146107e8578063d975dfed1461079b578063e985e9c514610748578063ea5ead1914610721578063eac8f5b8146106ce578063f590c17614610671578063f851a4401461064b5763fdd46d601461024f575f80fd5b346104d65760603660031901126104d6576004359061026c6131fd565b61027461335f565b9261027d613ad0565b808352600960205260ff600160408520015460a81c161561063a57808352600960205260ff600160408520015460a01c16610628576001600160a01b038216938415610615576001600160801b03811680156106025782855260036020526001600160a01b0360408620541680871415806105f2575b6105d7576001600160801b036103088561431a565b168083116105bc575083865260096020526001600160a01b0360408720541691848752600960205280600260408920015460801c01976001600160801b0389116105a8576103808899878a526009602052600260408b2001906001600160801b036001600160801b031983549260801b169116179055565b8588526009602052610397600260408a2001613652565b6001600160801b036103bb8160208401511692826040818351169201511690613397565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c88614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb91613321565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b8161055391613321565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b602488634e487b7160e01b81526011600452fd5b86606491848763287ecaef60e21b8452600452602452604452fd5b606486888663b34359d360e01b835260045233602452604452fd5b506105fc84613b2a565b156102f3565b6024858463d2aabcd960e01b8252600452fd5b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576004359061073f6131fd565b6102748361431a565b50346104d65760403660031901126104d6576001600160a01b03604061076c6131e7565b92826107766131fd565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d78361431a565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d6576004356108a6816137dc565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa90811561099d578291610916575b60405160208082528190610912908201856131c2565b0390f35b90503d8083833e6109278183613321565b8101906020818303126109955780519067ffffffffffffffff8211610999570181601f820112156109955780519261095e84613343565b9261096c6040519485613321565b848452602085840101116104d657506109129261098f91602080850191016131a1565b5f6108fc565b8280fd5b8380fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d657600435906109c66131fd565b916109cf613ad0565b808252600960205260ff600160408420015460a81c1615610e4e5780825260036020526001600160a01b0360408320541692833303610e3757610a118261431a565b6001600160801b0381169081158015610a99575b5050506001600160a01b03811615610a8657610a49826001600160a01b0392613984565b1680610a625760248383637e27328960e01b8252600452fd5b90838203610a6e578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610aa1613ad0565b848652600960205260ff600160408820015460a81c1615610e2557848652600960205260ff600160408820015460a01c16610e12578615610dff57610dec5783855260036020526001600160a01b036040862054168087141580610ddc575b610dc1576001600160801b03610b158661431a565b16808411610da6575084865260096020526001600160a01b0360408720541692858752600960205280600260408920015460801c016001600160801b0381116105a857610b8b908789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b8587526009602052610ba260026040892001613652565b6001600160801b03610bc68160208401511692826040818351169201511690613397565b161115610d6a575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610c18818688614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610d60575b610cf5575b823314159081610cea575b81610cdf575b50610c75575b80610a25565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610c6f5781610cd491613321565b61099557825f610c6f565b90508214155f610c69565b833b15159150610c63565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610d4b575b5050610c58565b81610d5591613321565b61055e57855f610d44565b50803b1515610c53565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610bce565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610de685613b2a565b15610b00565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610f506131e7565b610f586131fd565b906064359067ffffffffffffffff821161099957366023830112156109995781600401359284610f8785613343565b93610f956040519586613321565b8585523660248783010111610fc35785610fc096602460209301838801378501015260443591613698565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b57611052906138f0565b60405190600581101561106757602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d6576101403660031901126104d6576110a7613ad0565b6110af613634565b9064ffffffffff421680835264ffffffffff6110c9613684565b166111ee575b60e4359064ffffffffff82168203610995570164ffffffffff1660408301526001600160a01b03600435908116929083810361099557506024356001600160a01b0381169081810361099957506044356001600160801b038116908181036104d957506064356001600160a01b0381168091036104d95760843591821515928381036111ea575060a43593841515948581036111e65750604051976111738961327e565b8852602088015260408701526060860152608085015260a084015260c08301526040610103193601126104d657604051906111ad82613305565b61010435906001600160a01b03821682036104d65760206111de8585858152610124358482015260e0820152613c20565b604051908152f35b8780fd5b8680fd5b64ffffffffff6111fc613684565b82011660208401526110cf565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576112766131e7565b60243590811515809203610995576001600160a01b03169081156112e657338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611415575b602084108114611401578386529081156113da575060011461137d575b6109128461136981860382613321565b6040519182916020835260208301906131c2565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106113c05750909150810160200161136982611359565b9192600181602092548385880101520191019092916113a7565b60ff191660208087019190915292151560051b850190920192506113699150839050611359565b602483634e487b7160e01b81526022600452fd5b92607f169261133c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c161561107b576114a9906138f0565b90600582101590816114ea57600283149182156114fe575b82156114d5575b6020836040519015158152f35b9091506114ea57506004602091145f806114c8565b80634e487b7160e01b602492526021600452fd5b50600383149150806114c1565b50346104d65760203660031901126104d6576004359080610160604051611531816132cb565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611574613634565b6101408201520152818152600960205260ff600160408320015460a81c16156106bd5781815260096020526040812091604051906115b1826132e8565b8354906001600160a01b0382168352602083019464ffffffffff8360a01c168652604084019464ffffffffff8460c81c168652606085019060ff8560f01c1615158252608086019460f81c1515855260018301549560a08101966001600160a01b038116885260c082019660ff8260a01c1615158852611652600260e085019760ff8560a81c161515895260ff61010087019560b01c161515855201613652565b6101208401908152611663886138f0565b60058110156117f9576002146117f1575b5198516001600160a01b031693878152600a602052604081205464ffffffffff169a5164ffffffffff1695511515925115159851151596511515978152600360205260409020546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516116e9816132cb565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b848652611674565b602486634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff8111610fc35761183f90369060040161324d565b90611848613ad0565b82915b808310611856578380f35b611861838284613610565b359261186b613ad0565b838552600960205260ff600160408720015460a81c1615611b9f578385526009602052604085206001015460a01c60ff16156118b45760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611b8d576118e9815f5260096020526001600160a01b0360405f205416331490565b15611b77576118f78161380f565b90808652600960205261190f60026040882001613652565b916001600160801b038351166001600160801b0382161015611b6457818752600960205260ff604088205460f01c1615611b515790611966826001600160801b036020818796818d99511603169501511690613397565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611b2c575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a906001600160a01b03600160408d2001541694611a688b8588614340565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611ad4575b505050505050600101919061184b565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611b17575b80808080611ac4565b81611b2191613321565b61099957835f611b0e565b818552600960205260016040862001600160a01b60ff60a01b198254161790556119c7565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590611bcf613ad0565b818152600960205260ff600160408320015460a81c16156106bd57611bf3826138f0565b6005811015611d925760048103611c175750602491634a5541ef60e01b8252600452fd5b60038103611c32575060249163fe19f19f60e01b8252600452fd5b600214611d8057611c57825f5260096020526001600160a01b0360405f205416331490565b15611d6a57818152600960205260ff604082205460f01c1615611d5857818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611cfd575050f35b813b15611d545782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611d435750f35b81611d4d91613321565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b038116809103610fc3576001600160a01b03825416338103611e83575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f198101908111611e6f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760408160209364ffffffffff9352600a8452205416604051908152f35b50346104d65760203660031901126104d657611f1a6131e7565b9080546001600160a01b038116338103611e8357506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b03611f946131e7565b168015611fb1578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020611ffc6004356137dc565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d6576004359061202b613634565b50818152600960205260ff600160408320015460a81c16156106bd57816060928252600960205264ffffffffff6040818185205460a01c1693838152600a6020528282822054169381526009602052205460c81c16906040519261208e846132af565b8352602083015260408201526120c6604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b50346104d6576101603660031901126104d6576120e3613ad0565b604051906120f08261327e565b6120f86131e7565b82526121026131fd565b602083015261210f61335f565b60408301526064356001600160a01b0381168103610fc35760608301526084358015158103610fc357608083015260a4358015158103610fc35760a083015260603660c31901126104d657604051612166816132af565b60c43564ffffffffff8116810361099557815260e43564ffffffffff811681036109955760208201526101043564ffffffffff8116810361099557604082015260c08301526040610123193601126104d657604051906121c582613305565b61012435906001600160a01b03821682036104d65760206111de8585858152610144358482015260e0820152613c20565b50346104d65760403660031901126104d65760043567ffffffffffffffff8111610fc35761222890369060040161324d565b9060243567ffffffffffffffff81116109995761224990369060040161324d565b612251613ad0565b80840361267f57845b848110612265578580f35b612270818686613610565b3561227c828787613610565b35875260036020526001600160a01b036040882054169061229e838587613610565b356001600160801b03811680820361267b576122b8613ad0565b828a52600960205260ff600160408c20015460a81c161561266957828a52600960205260ff600160408c20015460a01c1661265657831561264357801561263057828a5260036020526001600160a01b0360408b205416908185141580612620575b612605576001600160801b0361232f8561431a565b168082116125ea5750908a91848352600960205280600260406001600160a01b03818720541695888152600960205220015460801c016001600160801b0381116125d657906123ad86959493928e989789526009602052600260408a2001906001600160801b036001600160801b031983549260801b169116179055565b84875260096020526123c460026040892001613652565b6001600160801b036123e88160208401511692826040818351169201511690613397565b16111561259a575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461243a818688614340565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580612590575b612525575b81331415908161251a575b8161250f575b5061249e575b505050505060010161225a565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16124fa575b808080612491565b8161250491613321565b61055e57855f6124f2565b90508114155f61248b565b823b15159150612485565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af161257b575b505061247a565b8161258591613321565b61055e57855f612574565b50803b1515612475565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556123f0565b60248d634e487b7160e01b81526011600452fd5b8b906064928663287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061262a84613b2a565b1561231a565b60248a8463d2aabcd960e01b8252600452fd5b60248a84630ff7ee2d60e31b8252600452fd5b60248a84634a5541ef60e01b8252600452fd5b60248a8462b8e7e760e51b8252600452fd5b8980fd5b84604491857faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5760206107d783613b9c565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd5780612726836138f0565b926005841015611d9257600260209403612747575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061273b565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d6576004356127a5613ad0565b808252600960205260ff600160408420015460a81c161561107b57808252600960205260ff600160408420015460a01c161561293a576127e481613b2a565b156129245780825260036020526001600160a01b0360408320541615158061291d575b80612900575b6128ee577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b0360408320541680159081156128b7575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506128a5575080f35b637e27328960e01b8252600452602490fd5b6128d6835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561285b565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c161561280d565b5081612807565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d657610fc061297736613213565b9060405192612987602085613321565b858452613698565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106bd57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612c6d576020366003190112612c6d57600435906129ff613ad0565b815f52600960205260ff600160405f20015460a81c1615612ce457815f52600960205260ff600160405f20015460a01c165f14612a495750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612cd257612a7c815f5260096020526001600160a01b0360405f205416331490565b15612cbc57612a8a8161380f565b90805f526009602052612aa2600260405f2001613652565b916001600160801b038351166001600160801b0382161015612ca957815f52600960205260ff60405f205460f01c1615612c9657806001600160801b03602081612af6948188511603169501511690613397565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612c71575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612be16001600160a01b03600160405f2001541694611a688b8588614340565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612c18578580f35b813b15612c6d575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612c5a575b808080808580f35b612c6691505f90613321565b5f80612c52565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612b40565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612c6d57612d0d612d0736613213565b916133cb565b005b34612c6d575f366003190112612c6d576020600754604051908152f35b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da457612d64906138f0565b6005811015612d90578060209115908115612d85575b506040519015158152f35b600191501482612d7a565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612c6d576020366003190112612c6d57600435805f52600960205260ff600160405f20015460a81c1615612da4576020905f90805f526009835260ff60405f205460f01c1680612e4a575b612e18575b506001600160801b0360405191168152f35b612e449150805f5260098352612e3e6001600160801b03600260405f200154169161380f565b90613397565b82612e06565b50805f526009835260ff600160405f20015460a01c1615612e01565b34612c6d576040366003190112612c6d57612e7f6131e7565b602435612e8b816137dc565b33151580612f58575b80612f25575b612ef95781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612e9a565b50336001600160a01b0382161415612e94565b34612c6d576020366003190112612c6d576020611ffc600435613375565b34612c6d575f366003190112612c6d576040515f6001548060011c90600181168015613073575b60208310811461305f5782855290811561303b5750600114612fdd575b6109128361136981850382613321565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061302157509091508101602001611369612fcd565b919260018160209254838588010152019101909291613009565b60ff191660208086019190915291151560051b840190910191506113699050612fcd565b634e487b7160e01b5f52602260045260245ffd5b91607f1691612fb0565b34612c6d575f366003190112612c6d57602060405167016345785d8a00008152f35b34612c6d576020366003190112612c6d57600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612c6d57817f490649060000000000000000000000000000000000000000000000000000000060209314908115613113575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613177575b811561314d575b508361310c565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483613146565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061313f565b5f5b8381106131b25750505f910152565b81810151838201526020016131a3565b906020916131db815180928185528580860191016131a1565b601f01601f1916010190565b600435906001600160a01b0382168203612c6d57565b602435906001600160a01b0382168203612c6d57565b6060906003190112612c6d576004356001600160a01b0381168103612c6d57906024356001600160a01b0381168103612c6d579060443590565b9181601f84011215612c6d5782359167ffffffffffffffff8311612c6d576020808501948460051b010111612c6d57565b610100810190811067ffffffffffffffff82111761329b57604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761329b57604052565b610180810190811067ffffffffffffffff82111761329b57604052565b610140810190811067ffffffffffffffff82111761329b57604052565b6040810190811067ffffffffffffffff82111761329b57604052565b90601f8019910116810190811067ffffffffffffffff82111761329b57604052565b67ffffffffffffffff811161329b57601f01601f191660200190565b604435906001600160801b0382168203612c6d57565b61337e816137dc565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116133b757565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156135fd57815f5260036020526001600160a01b0360405f2054161515806135f5575b806135d8575b6135c5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613510575b6001600160a01b039350856134d9575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036134c157505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6134f8825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613460565b919290508061356e575b1561352757828291613450565b828461353f57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b50338414801561359c575b8061351a5750825f526005602052336001600160a01b0360405f2054161461351a565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613579565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c1615613400565b5060016133fa565b633250574960e11b5f525f60045260245ffd5b91908110156136205760051b0190565b634e487b7160e01b5f52603260045260245ffd5b60405190613641826132af565b5f6040838281528260208201520152565b9060405161365f816132af565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff81168103612c6d5790565b906136a48382846133cb565b803b6136b1575b50505050565b6020916136f76001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906131c2565b03815f865af15f918161377f575b5061373357506137136142eb565b8051908161372e5782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b91160361376d57505f8080806136ab565b633250574960e11b5f5260045260245ffd5b9091506020813d6020116137d4575b8161379b60209383613321565b81010312612c6d57517fffffffff0000000000000000000000000000000000000000000000000000000081168103612c6d57905f613705565b3d915061378e565b805f5260036020526001600160a01b0360405f2054169081156137fd575090565b637e27328960e01b5f5260045260245ffd5b805f52600a60205264ffffffffff60405f205416815f52600960205264ffffffffff60405f205460a01c1690421080156138e7575b6138e157815f52600960205264ffffffffff60405f205460c81c1690814210156138c4578061387692039042036144ce565b815f5260096020526138996001600160801b03600260405f2001541680926145ba565b9081116138ae576001600160801b0391501690565b505f526009602052600260405f20015460801c90565b50505f5260096020526001600160801b03600260405f2001541690565b50505f90565b50428111613844565b805f52600960205260ff600160405f20015460a01c165f146139125750600490565b805f52600960205260405f205460f81c61397e57805f52600960205264ffffffffff60405f205460a01c1642106139795761394c8161380f565b905f5260096020526001600160801b0380600260405f200154169116105f1461397457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613abe575b80613aa1575b613a8f577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a58575b1680613a40575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f20600181540190556139fc565b613a77835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f1981540190556139f5565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c16156139a9565b506001600160a01b03821615156139a3565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0257565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b70575b508115613b57575090565b90506001600160a01b03613b6b3392613375565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b4c565b805f526009602052613bb3600260405f2001613652565b90805f52600960205260ff600160405f20015460a01c165f14613be15750602001516001600160801b031690565b90815f52600960205260405f205460f81c613c035750613c009061380f565b90565b613c0091506001600160801b036040818351169201511690613397565b90613c416001600160801b03604084015116602060e0850151015190614397565b916001600160801b0383511660c082015190156142c35764ffffffffff8151161561429b576020810164ffffffffff8151168061420f575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e157505064ffffffffff80421691511690818110156141b35750506007549280516001600160801b03169160405192613cd1846132af565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d37896132e8565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600960205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fb791906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614193575b50600185016007556001600160a01b0360208201511680156135fd57614025866001600160a01b0392613984565b16614167576140506001600160a01b036060830151166001600160801b038451169030903390614474565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614138575b5061412f6001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614161906001600160a01b036060880151166001600160a01b0360e08901515116903390614474565b5f61408b565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600a60205260405f209064ffffffffff198254161790555f613ff7565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561426d57505064ffffffffff90511664ffffffffff60408301511690818110613c79577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614315573d906142fc82613343565b9161430a6040519384613321565b82523d5f602084013e565b606090565b613c009061432781613b9c565b905f526009602052600260405f20015460801c90613397565b614395926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614390606483613321565b614668565b565b9190916040516143a681613305565b5f81525f6020820152926001600160801b0382169081156144575767016345785d8a00008111614420576143e26001600160801b0391836145ba565b166020850191818352111561440c576001600160801b03918261440792511690613397565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446881613305565b5f81525f602082015290565b9091926001600160a01b036143959481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614390608483613321565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614599578184101561455f57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145a6570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465757670de0b6b3a7640000821015614627577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469193169360208151910182865af161468a6142eb565b90836146f6565b80519081151591826146d2575b50506146a75750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612c6d5760200151801590811503612c6d575f8061469e565b90614733575080511561470b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614779575b614744575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473c56fea164736f6c634300081a000a"; + hex"60a0604052346103bf57614ac56040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146dc90816103e9823960805181613a300152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a557508063027b67441461308357806306fdde0314612fc8578063081812fc14612faa578063095ea7b314612ea55780631400ecec14612df45780631c1cdd4c14612d905780631e99d56914612d7357806323b872dd14612d5c578063303acc8514612d1f578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131d2565b90610288613334565b610290613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c85614270565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f2001613600565b6001600160801b036103b6816020840151169282604081835116920151169061336c565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f6565b810190613736565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a80565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131d2565b906106eb81614270565b6106f3613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f85614270565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f2001613600565b6001600160801b03610819816020840151169282604081835116920151169061336c565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f6565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a80565b1561076a565b346105f05760403660031901126105f0576109916131bc565b6001600160a01b036109a16131d2565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091614270565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613756565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613197565b0390f35b503d805f833e610b5681836132f6565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613318565b91610b9c60405193846132f6565b838352602084830101116105f057610b4292610bbe9160208085019101613176565b610b2a565b346105f05760403660031901126105f057600435610bdf6131d2565b90610be8613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c3283614270565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ec565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a26565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d4385614270565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f2001613600565b6001600160801b03610ddd816020840151169282604081835116920151169061336c565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614296565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f6565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a80565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131bc565b6110ba6131d2565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613318565b926110f560405194856132f6565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613646565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613858565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a26565b6111f46135e2565b64ffffffffff421680825264ffffffffff61120d613632565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613253565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132da565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b76565b604051908152f35b64ffffffffff611336613632565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131bc565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f6565b604051918291602083526020830190613197565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613858565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f610160604051611643816132a0565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135e2565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132bd565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c161515845201613600565b610120830190815261177187613858565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f7816132a0565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f057611938903690600401613222565b90611941613a26565b5f915b80831061194d57005b6119588382846135be565b3592611962613a26565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613777565b90805f52600a602052611a07600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b94818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614296565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f6565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a26565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613858565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131bc565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131bc565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613756565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135e2565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613284565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a26565b60405161211581613253565b61211d6131bc565b81526121276131d2565b6020820152612134613334565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613284565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132da565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b76565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b903690600401613222565b60243567ffffffffffffffff81116105f05761226b903690600401613222565b612276939193613a26565b8083036125b8575f5b83811061228857005b6122938185856135be565b3561229f8286866135be565b355f5260036020526001600160a01b0360405f205416906122c18385896135be565b356001600160801b038116908181036105f057506122dd613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b0361235484614270565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f2001613600565b6001600160801b036123ee816020840151169282604081835116920151169061336c565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f6565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a80565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af2565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613858565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a80565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e8565b906040519261289d6020856132f6565b5f8452613646565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613777565b90805f52600a6020526129b2600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a0694818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614296565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131bc565b6001600160a01b035f541690338203612d0857806001600160a01b03913b15612cdc57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612cad575b5015612c82576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccf915060203d602011612cd5575b612cc781836132f6565b8101906135a6565b82612c34565b503d612cbd565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d406131bc565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6d366131e8565b9161338c565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc890613858565b60058110156111be578060209115908115612de9575b506040519015158152f35b600191501482612dde565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e89575b612e57575b506001600160801b0360405191168152f35b612e839150805f52600a8352612e7d6001600160801b03600260405f2001541691613777565b9061336c565b82612e45565b50805f52600a835260ff600160405f20015460a01c1615612e40565b346105f05760403660031901126105f057612ebe6131bc565b602435612eca81613756565b33151580612f97575b80612f64575b612f385781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed9565b50336001600160a01b0382161415612ed3565b346105f05760203660031901126105f057602061201860043561334a565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613079575b6020831081146115325782855290811561150e575060011461301b57610b428361149c818503826132f6565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305f5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613047565b91607f1691612fef565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f490649060000000000000000000000000000000000000000000000000000000060209314908115613101575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561314c575b811561313b575b50836130fa565b6301ffc9a760e01b91501483613134565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312d565b5f5b8381106131875750505f910152565b8181015183820152602001613178565b906020916131b081518092818552858086019101613176565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761327057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761327057604052565b610180810190811067ffffffffffffffff82111761327057604052565b610140810190811067ffffffffffffffff82111761327057604052565b6040810190811067ffffffffffffffff82111761327057604052565b90601f8019910116810190811067ffffffffffffffff82111761327057604052565b67ffffffffffffffff811161327057601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335381613756565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359e575b80613581575b61356e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b9575b6001600160a01b03935085613482575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b6134a1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613421565b9192905080613517575b156134d057828291613411565b82846134e857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613545575b806134c35750825f526005602052336001600160a01b0360405f205416146134c3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613522565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133c1565b5060016133bb565b908160209103126105f0575180151581036105f05790565b91908110156135ce5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ef82613284565b5f6040838281528260208201520152565b9060405161360d81613284565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061365283828461338c565b803b61365f575b50505050565b6020916136a56001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613197565b03815f865af15f9181613715575b506136e157506136c1614241565b805190816136dc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370357505f808080613659565b633250574960e11b5f5260045260245ffd5b61372f91925060203d6020116104f2576104e481836132f6565b905f6136b3565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384f575b61384957815f52600a60205264ffffffffff60405f205460c81c16908142101561382c57806137de9203904203614424565b815f52600a6020526138016001600160801b03600260405f200154168092614510565b908111613816576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281116137ac565b805f52600a60205260ff600160405f20015460a01c165f1461387a5750600490565b805f52600a60205260405f205460f81c6138e657805f52600a60205264ffffffffff60405f205460a01c1642106138e1576138b481613777565b905f52600a6020526001600160801b0380600260405f200154169116105f146138dc57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a14575b806139f7575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139c0575b16806139a8575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613964565b6139df835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395d565b50805f52600a60205260ff600160405f20015460b01c1615613911565b506001600160a01b038216151561390b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5857565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac6575b508115613aad575090565b90506001600160a01b03613ac1339261334a565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa2565b805f52600a602052613b09600260405f2001613600565b90805f52600a60205260ff600160405f20015460a01c165f14613b375750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b595750613b5690613777565b90565b613b5691506001600160801b03604081835116920151169061336c565b90613b976001600160801b03604084015116602060e08501510151906142ed565b916001600160801b0383511660c082015190156142195764ffffffffff815116156141f1576020810164ffffffffff81511680614165575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413757505064ffffffffff80421691511690818110156141095750506007549280516001600160801b03169160405192613c2784613284565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8d896132bd565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0d91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140e9575b50600185016007556001600160a01b036020820151168015610cb357613f7b866001600160a01b03926138ec565b166140bd57613fa66001600160a01b036060830151166001600160801b0384511690309033906143ca565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408e575b506140856001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b7906001600160a01b036060880151166001600160a01b0360e089015151169033906143ca565b5f613fe1565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4d565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c357505064ffffffffff90511664ffffffffff60408301511690818110613bcf577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561426b573d9061425282613318565b9161426060405193846132f6565b82523d5f602084013e565b606090565b613b569061427d81613af2565b905f52600a602052600260405f20015460801c9061336c565b6142eb926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e66064836132f6565b6145be565b565b9190916040516142fc816132da565b5f81525f6020820152926001600160801b0382169081156143ad5767016345785d8a00008111614376576143386001600160801b039183614510565b1660208501918183521115614362576001600160801b03918261435d9251169061336c565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143be816132da565b5f81525f602082015290565b9091926001600160a01b036142eb9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e66084836132f6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144ef57818410156144b557670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fc570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ad57670de0b6b3a764000082101561457d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e793169360208151910182865af16145e0614241565b9083614643565b8051908115159182614628575b50506145fd5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463b92506020809183010191016135a6565b155f806145f4565b90614680575080511561465857805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c6575b614691575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468956fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e457614ef06060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614ae2908161040e823960805181613eeb015260a051818181612f4e0152613f940152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a71461331a57508063027b6744146132f857806306fdde0314613204578063081812fc146131e6578063095ea7b3146130e15780631400ecec146130305780631c1cdd4c14612fa75780631e99d56914612f8a57806323b872dd14612f715780632fe4304114612f3757806332fbe22b14612dda57806340e58ee514612ac5578063425d30dd14612a7357806342842e0e14612a4957806342966c681461286c57806344267570146128455780634857501f146127cf5780634869e12d146127935780634cc55e111461230157806357404b12146122695780636352211e146122395780636d0cee751461223957806370a08231146121ce57806375829def1461215c5780637cad6cd1146120505780637de6b1db14611e5b5780637f5799f914611dff5780638659c27014611a5b578063894e9a0d14611707578063897f362b146114395780638f69b9931461139e5780639067b6771461134d57806395d89b4114611240578063a22cb4651461118a578063a80fc07114611137578063ad35efd4146110c4578063b256456914611072578063b88d4fde14610fe1578063b8a3be6614610fac578063b971302a14610f5c578063bc2be1be14610f0b578063c156a11d14610a60578063c87b56dd14610944578063d4dbd20b146108f1578063d511609f146108a4578063d975dfed14610857578063e985e9c514610804578063ea5ead1914610713578063eac8f5b8146106c0578063f590c17614610663578063f851a4401461063d5763fdd46d601461025a575f80fd5b346104d65760603660031901126104d65760043590610277613478565b604435926001600160801b0384169384810361063957610295613ee1565b818452600960205260ff600160408620015460a81c161561062757818452600960205260ff600160408620015460a01c16610614576001600160a01b03831680156106015785156105ee5782855260036020526001600160a01b0360408620541680821415806105de575b6105c3576001600160801b0361031585614739565b168088116105a85750859684875260096020526001600160a01b0360408820541692858852600960205261035385600260408b20015460801c61475f565b8689526009602052600260408a2001906001600160801b036001600160801b031983549260801b1691161790558588526009602052610397600260408a2001613a2f565b6001600160801b036103bb8160208401511692826040818351169201511690613663565b16111561056c575b8588526009602052857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d200154169461040c818c886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18033141580610562575b6104f3575b8133141590816104e8575b816104dd575b50610466578480f35b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16104c1575b8080808480f35b816104cb916135ef565b6104d657805f6104ba565b80fd5b8480fd5b90508114155f61045d565b823b15159150610457565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1610549575b505061044c565b81610553916135ef565b61055e57855f610542565b8580fd5b50803b1515610447565b858852600960205260016040892001600160a01b60ff60a01b1982541617905585885260096020526040882060ff60f01b1981541690556103c3565b86606491898763287ecaef60e21b8452600452602452604452fd5b606486838663b34359d360e01b835260045233602452604452fd5b506105e884614614565b15610300565b6024858463d2aabcd960e01b8252600452fd5b60248584630ff7ee2d60e31b8252600452fd5b60248483634a5541ef60e01b8252600452fd5b6024848362b8e7e760e51b8252600452fd5b8380fd5b50346104d657806003193601126104d6576001600160a01b036020915416604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57806020926040925260098352205460f81c6040519015158152f35b60249162b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760016040826020946001600160a01b0394526009855220015416604051908152f35b50346104d65760403660031901126104d65760043590610731613478565b61073a83614739565b92610743613ee1565b808352600960205260ff600160408520015460a81c16156107f357808352600960205260ff600160408520015460a01c166107e1576001600160a01b0382169384156107ce576001600160801b0381169485156105ee5782855260036020526001600160a01b0360408620541680821415806105de576105c3576001600160801b0361031585614739565b60248483630ff7ee2d60e31b8252600452fd5b634a5541ef60e01b8352600452602482fd5b62b8e7e760e51b8352600452602482fd5b50346104d65760403660031901126104d6576001600160a01b036040610828613462565b9282610832613478565b9416815260066020522091165f52602052602060ff60405f2054166040519015158152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614739565b6001600160801b0360405191168152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57604081602093600293526009845220015460801c604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760036040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760203660031901126104d65760043561096281613bc6565b50816001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa908115610a555782916109d2575b604051602080825281906109ce9082018561343d565b0390f35b90503d8083833e6109e381836135ef565b810190602081830312610a515780519067ffffffffffffffff8211610639570181601f82011215610a5157805192610a1a84613611565b92610a2860405194856135ef565b848452602085840101116104d657506109ce92610a4b916020808501910161341c565b5f6109b8565b8280fd5b6040513d84823e3d90fd5b50346104d65760403660031901126104d65760043590610a7e613478565b91610a87613ee1565b808252600960205260ff600160408420015460a81c1615610ef95780825260036020526001600160a01b0360408320541692833303610ee257610ac982614739565b6001600160801b0381169081158015610b51575b5050506001600160a01b03811615610b3e57610b01826001600160a01b0392613d95565b1680610b1a5760248383637e27328960e01b8252600452fd5b90838203610b26578280f35b6064936364283d7b60e01b8452600452602452604452fd5b602483633250574960e11b815280600452fd5b610b59613ee1565b848652600960205260ff600160408820015460a81c1615610ed057848652600960205260ff600160408820015460a01c16610ebd578615610eaa57610e975783855260036020526001600160a01b036040862054168087141580610e87575b610e6c576001600160801b03610bcd86614739565b16808411610e51575084865260096020526001600160a01b03604087205416928587526009602052610c0983600260408a20015460801c61475f565b868852600960205260026040892001906001600160801b036001600160801b031983549260801b1691161790558587526009602052610c4d60026040892001613a2f565b6001600160801b03610c718160208401511692826040818351169201511690613663565b161115610e15575b858752600960205287867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d2001541694610cc38186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610e0b575b610da0575b823314159081610d95575b81610d8a575b50610d20575b80610add565b813b156104d957604051636fd110e960e01b8152600481018590523360248201526001600160a01b03871660448201526001600160801b03919091166064820152849182908290608490829084905af115610d1a5781610d7f916135ef565b610a5157825f610d1a565b90508214155f610d14565b833b15159150610d0e565b803b1561055e57604051636fd110e960e01b8152600481018690523360248201526001600160a01b03881660448201526001600160801b03831660648201528690818160848183875af1610df6575b5050610d03565b81610e00916135ef565b61055e57855f610def565b50803b1515610cfe565b858752600960205260016040882001600160a01b60ff60a01b1982541617905585875260096020526040872060ff60f01b198154169055610c79565b86606491858863287ecaef60e21b8452600452602452604452fd5b606486888763b34359d360e01b835260045233602452604452fd5b50610e9185614614565b15610bb8565b6024858563d2aabcd960e01b8252600452fd5b60248686630ff7ee2d60e31b8252600452fd5b60248686634a5541ef60e01b8252600452fd5b6024868662b8e7e760e51b8252600452fd5b6044838363216caf0d60e01b825260045233602452fd5b6024925062b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460a01c16604051908152f35b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816020936001600160a01b03935260098452205416604051908152f35b50346104d65760203660031901126104d65760ff6001604060209360043581526009855220015460a81c166040519015158152f35b50346104d65760803660031901126104d657610ffb613462565b611003613478565b906064359067ffffffffffffffff82116106395736602383011215610639578160040135928461103285613611565b9361104060405195866135ef565b858552366024878301011161106e578561106b96602460209301838801378501015260443591613a82565b80f35b5080fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460b01c166040519015158152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576110fd90613d01565b60405190600581101561111257602092508152f35b602483634e487b7160e01b81526021600452fd5b62b8e7e760e51b8252600452602490fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760026040826020946001600160801b0394526009855220015416604051908152f35b50346104d65760403660031901126104d6576111a4613462565b60243590811515809203610a51576001600160a01b031690811561121457338352600660205260408320825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b602483837f5b08ba18000000000000000000000000000000000000000000000000000000008252600452fd5b50346104d657806003193601126104d6576040519080600254908160011c91600181168015611343575b60208410811461132f5783865290811561130857506001146112ab575b6109ce84611297818603826135ef565b60405191829160208352602083019061343d565b600281527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace939250905b8082106112ee5750909150810160200161129782611287565b9192600181602092548385880101520191019092916112d5565b60ff191660208087019190915292151560051b850190920192506112979150839050611287565b602483634e487b7160e01b81526022600452fd5b92607f169261126a565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af5760408160209364ffffffffff935260098452205460c81c16604051908152f35b50346104d65760203660031901126104d657600435808252600960205260ff600160408420015460a81c1615611126576113d790613d01565b9060058210159081611418576002831491821561142c575b8215611403575b6020836040519015158152f35b90915061141857506004602091145f806113f6565b80634e487b7160e01b602492526021600452fd5b50600383149150806113ef565b50346104d65760203660031901126104d6576004359067ffffffffffffffff82116104d65781360361012060031982011261106e57611476613ee1565b60c4830135906022190181121561106e57820160048101359067ffffffffffffffff8211610a515760248101908260061b80360383136104d95760046020916114be866138ee565b956114cc60405197886135ef565b865282860193010101913683116104d957905b8282106116ed575050508051916114f5836138ee565b9261150360405194856135ef565b808452601f19611512826138ee565b01825b8181106116ca57505064ffffffffff4216926001600160801b0361153882613bf9565b51511664ffffffffff80602061154d85613bf9565b51015116860116604051916115618361359a565b8252602082015261157186613bf9565b5261157b85613bf9565b5060015b8281106116555750505061159584600401613a61565b906115a260248601613a61565b906115af6044870161398f565b6064870135916001600160a01b0383168093036104d657602061164d61160d6116428b8b8b8b8b8b6001600160801b038c6001600160a01b036115f460848a01613a75565b948161160260a48c01613a75565b976040519d8e613569565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161393c565b610100820152613f3b565b604051908152f35b806001600160801b0361166a60019385613c06565b51511664ffffffffff8060206116835f1986018c613c06565b510151168160206116948689613c06565b510151160116604051916116a78361359a565b825260208201526116b88289613c06565b526116c38188613c06565b500161157f565b6020906040516116d98161359a565b5f81525f8382015282828901015201611515565b60206040916116fc3685613906565b8152019101906114df565b50346104d65760203660031901126104d657600435606061016060405161172d816135b6565b84815284602082015284604082015284838201528460808201528460a08201528460c08201528460e08201528461010082015284610120820152604051611773816135d3565b8581528560208201528560408201526101408201520152808252600960205260ff600160408420015460a81c1615611126578082526009602052604082209060405192610140840184811067ffffffffffffffff821117611a47576040528254906001600160a01b0382168552602085019364ffffffffff8360a01c168552856040810164ffffffffff8560c81c168152606082019460ff8160f01c1615158652608083019060f81c1515815260018401549360a08401966001600160a01b0386168852611870600260c087019360ff8960a01c161515855260ff61010060e08a0199828c60a81c1615158b52019960b01c161515895201613a2f565b6101208c019081526118818a613d01565b6005811015611a3357600214611a2b575b5197516001600160a01b0316935164ffffffffff169051151591511515945115159551151596898152600360205260408120546001600160a01b03169b516001600160a01b03169a5164ffffffffff16998152600a6020526040902092511515926040519a6119008c6135b6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611954906139bb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016109ce9161350d565b878252611892565b602489634e487b7160e01b81526021600452fd5b602482634e487b7160e01b81526041600452fd5b50346104d65760203660031901126104d65760043567ffffffffffffffff811161106e57611a8d9036906004016134dc565b90611a96613ee1565b82915b808310611aa4578380f35b611aaf83828461396b565b3592611ab9613ee1565b838552600960205260ff600160408720015460a81c1615611ded578385526009602052604085206001015460a01c60ff1615611b025760248585634a5541ef60e01b8252600452fd5b9091928085526009602052604085205460f81c611ddb57611b37815f5260096020526001600160a01b0360405f205416331490565b15611dc557611b4581613c1a565b908086526009602052611b5d60026040882001613a2f565b916001600160801b038351166001600160801b0382161015611db257818752600960205260ff604088205460f01c1615611d9f5790611bb4826001600160801b036020818796818d99511603169501511690613663565b90808452600960205260408420600160f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82541617905580845260096020526040842060ff60f01b1981541690556001600160801b038216918215611d7a575b8185526009602052600360408620016001600160801b0385166001600160801b031982541617905581855260096020526001600160a01b036040862054169180865260036020526001600160a01b0360408720541691818752600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611cde6001600160a01b03600160408d2001541694611cb68b85886148bd565b604080518881526001600160801b03808e166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b611d22575b5050505050506001019190611a99565b813b1561055e57856084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1611d65575b80808080611d12565b81611d6f916135ef565b61063957835f611d5c565b818552600960205260016040862001600160a01b60ff60a01b19825416179055611c15565b602487836339c6dc7360e21b8252600452fd5b602487836322cad1af60e11b8252600452fd5b63216caf0d60e01b855260045233602452604484fd5b63fe19f19f60e01b8552600452602484fd5b6024858562b8e7e760e51b8252600452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af576040816109ce93611e479352600a602052206139bb565b60405191829160208352602083019061350d565b50346104d65760203660031901126104d65760043590611e79613ee1565b818152600960205260ff600160408320015460a81c16156106af57611e9d82613d01565b600581101561203c5760048103611ec15750602491634a5541ef60e01b8252600452fd5b60038103611edc575060249163fe19f19f60e01b8252600452fd5b60021461202a57611f01825f5260096020526001600160a01b0360405f205416331490565b1561201457818152600960205260ff604082205460f01c161561200257818192825260096020526040822060ff60f01b1981541690557ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051837f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f8680a2838152a180825260036020526001600160a01b0360408320541690813b611fa7575050f35b813b15611ffe5782916024839260405194859384927f4501546400000000000000000000000000000000000000000000000000000000845260048401525af1611fed5750f35b81611ff7916135ef565b6104d65780f35b5050fd5b6024916339c6dc7360e21b8252600452fd5b60449163216caf0d60e01b825260045233602452fd5b6024916322cad1af60e11b8252600452fd5b602482634e487b7160e01b81526021600452fd5b50346104d65760203660031901126104d6576004356001600160a01b03811680910361106e576001600160a01b0382541633810361212d575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121195760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a180f35b602482634e487b7160e01b81526011600452fd5b7fc6cce6a400000000000000000000000000000000000000000000000000000000835260045233602452604482fd5b50346104d65760203660031901126104d657612176613462565b9080546001600160a01b03811633810361212d57506001600160a01b036001600160a01b031992931691829116178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b50346104d65760203660031901126104d6576001600160a01b036121f0613462565b16801561220d578160409160209352600483522054604051908152f35b6024827f89c62b6400000000000000000000000000000000000000000000000000000000815280600452fd5b50346104d65760203660031901126104d6576020612258600435613bc6565b6001600160a01b0360405191168152f35b50346104d65760203660031901126104d657600435906122876139a3565b50818152600960205260ff600160408320015460a81c16156106af579064ffffffffff604083838295526009602052828282205460a01c169381526009602052205460c81c168251916122d98361359a565b825260208201526122ff8251809264ffffffffff60208092828151168552015116910152565bf35b50346104d65760403660031901126104d65760043567ffffffffffffffff811161106e576123339036906004016134dc565b9060243567ffffffffffffffff8111610639576123549036906004016134dc565b9261235d613ee1565b83810361276357845b818110612371578580f35b61237c81838661396b565b3561238882848761396b565b35875260036020526001600160a01b03604088205416906123b26123ad84898861396b565b61398f565b6123ba613ee1565b818952600960205260ff600160408b20015460a81c161561275157818952600960205260ff600160408b20015460a01c1661273e57821561272b576001600160801b038116801561271857828a5260036020526001600160a01b0360408b2054168085141580612708575b6126ed576001600160801b0361243a85614739565b168083116126d25750908392918b9594865260096020526001600160a01b0360408720541691848752600960205261247c84600260408a20015460801c61475f565b858852600960205260026040892001906001600160801b036001600160801b031983549260801b16911617905584875260096020526124c060026040892001613a2f565b6001600160801b036124e48160208401511692826040818351169201511690613663565b161115612696575b848752600960205285857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d60206001600160a01b03600160408d20015416946125368186886148bd565b604051908152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1803314158061268c575b612621575b813314159081612616575b8161260b575b5061259a575b5050505050600101612366565b803b156104d957604051636fd110e960e01b815260048101939093523360248401526001600160a01b039390931660448301526001600160801b031660648201529082908290608490829084905af16125f6575b80808061258d565b81612600916135ef565b61055e57855f6125ee565b90508114155f612587565b823b15159150612581565b803b1561055e57604051636fd110e960e01b8152600481018590523360248201526001600160a01b03861660448201526001600160801b03841660648201528690818160848183875af1612677575b5050612576565b81612681916135ef565b61055e57855f612670565b50803b1515612571565b848752600960205260016040882001600160a01b60ff60a01b1982541617905584875260096020526040872060ff60f01b1981541690556124ec565b8b606491848763287ecaef60e21b8452600452602452604452fd5b60648b868663b34359d360e01b835260045233602452604452fd5b5061271284614614565b15612425565b60248a8463d2aabcd960e01b8252600452fd5b60248983630ff7ee2d60e31b8252600452fd5b60248983634a5541ef60e01b8252600452fd5b6024898362b8e7e760e51b8252600452fd5b84846044927faec93440000000000000000000000000000000000000000000000000000000008352600452602452fd5b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57602061089383614686565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af578061280a83613d01565b92600584101561203c5760026020940361282b575b50506040519015158152f35b815260098352604090205460f01c60ff1690505f8061281f565b50346104d657806003193601126104d65760206001600160a01b0360085416604051908152f35b50346104d65760203660031901126104d657600435612889613ee1565b808252600960205260ff600160408420015460a81c161561112657808252600960205260ff600160408420015460a01c1615612a1e576128c881614614565b15612a085780825260036020526001600160a01b03604083205416151580612a01575b806129e4575b6129d2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a180825260036020526001600160a01b03604083205416801590811561299b575b8284526003602052604084206001600160a01b031981541690558284827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612989575080f35b637e27328960e01b8252600452602490fd5b6129ba835f52600560205260405f206001600160a01b03198154169055565b80845260046020526040842080545f1901905561293f565b630da9b01360e01b8252600452602490fd5b50808252600960205260ff600160408420015460b01c16156128f1565b50816128eb565b63216caf0d60e01b825260045233602452604490fd5b7f817cd639000000000000000000000000000000000000000000000000000000008252600452602490fd5b50346104d65761106b612a5b366134a2565b9060405192612a6b6020856135ef565b858452613a82565b50346104d65760203660031901126104d65760043590818152600960205260ff600160408320015460a81c16156106af57600160408260209460ff94526009855220015460a01c166040519015158152f35b5034612d51576020366003190112612d515760043590612ae3613ee1565b815f52600960205260ff600160405f20015460a81c1615612dc857815f52600960205260ff600160405f20015460a01c165f14612b2d5750634a5541ef60e01b5f5260045260245ffd5b90805f52600960205260405f205460f81c612db657612b60815f5260096020526001600160a01b0360405f205416331490565b15612da057612b6e81613c1a565b90805f526009602052612b86600260405f2001613a2f565b916001600160801b038351166001600160801b0382161015612d8d57815f52600960205260ff60405f205460f01c1615612d7a57806001600160801b03602081612bda948188511603169501511690613663565b5f82815260096020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790556001600160801b03811691908215612d55575b815f526009602052600360405f20016001600160801b0385166001600160801b0319825416179055815f5260096020526001600160a01b0360405f20541691805f5260036020526001600160a01b0360405f20541691815f52600960205282847f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612cc56001600160a01b03600160405f2001541694611cb68b85886148bd565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1813b612cfc578580f35b813b15612d51575f6084928195604051978896879563c6f5ed0f60e01b875260048701526024860152604485015260648401525af1612d3e575b808080808580f35b612d4a91505f906135ef565b5f80612d36565b5f80fd5b815f526009602052600160405f2001600160a01b60ff60a01b19825416179055612c24565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d515760043567ffffffffffffffff8111612d51576101406003198236030112612d5157612e14613ee1565b604051612e2081613569565b612e2c8260040161348e565b8152612e3a6024830161348e565b6020820152612e4b6044830161362d565b604082015260648201356001600160a01b0381168103612d51576060820152612e766084830161355c565b6080820152612e8760a4830161355c565b60a0820152612e9860c483016138dc565b60c082015260e482013567ffffffffffffffff8111612d515782019136602384011215612d5157600483013592612ece846138ee565b90612edc60405192836135ef565b848252602060048184019660061b8301010190368211612d5157602401945b818610612f1d57602061164d86611642878760e084015261010436910161393c565b6020604091612f2c3689613906565b815201950194612efb565b34612d51575f366003190112612d515760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34612d5157612f88612f82366134a2565b91613697565b005b34612d51575f366003190112612d51576020600754604051908152f35b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f57612fdf90613d01565b600581101561300b578060209115908115613000575b506040519015158152f35b600191501482612ff5565b634e487b7160e01b5f52602160045260245ffd5b62b8e7e760e51b5f5260045260245ffd5b34612d51576020366003190112612d5157600435805f52600960205260ff600160405f20015460a81c161561301f576020905f90805f526009835260ff60405f205460f01c16806130c5575b613093575b506001600160801b0360405191168152f35b6130bf9150805f52600983526130b96001600160801b03600260405f2001541691613c1a565b90613663565b82613081565b50805f526009835260ff600160405f20015460a01c161561307c565b34612d51576040366003190112612d51576130fa613462565b60243561310681613bc6565b331515806131d3575b806131a0575b6131745781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613115565b50336001600160a01b038216141561310f565b34612d51576020366003190112612d51576020612258600435613641565b34612d51575f366003190112612d51576040515f6001548060011c906001811680156132ee575b6020831081146132da578285529081156132b65750600114613258575b6109ce83611297818503826135ef565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061329c57509091508101602001611297613248565b919260018160209254838588010152019101909291613284565b60ff191660208086019190915291151560051b840190910191506112979050613248565b634e487b7160e01b5f52602260045260245ffd5b91607f169161322b565b34612d51575f366003190112612d5157602060405167016345785d8a00008152f35b34612d51576020366003190112612d5157600435907fffffffff000000000000000000000000000000000000000000000000000000008216809203612d5157817f49064906000000000000000000000000000000000000000000000000000000006020931490811561338e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133f2575b81156133c8575b5083613387565b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836133c1565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506133ba565b5f5b83811061342d5750505f910152565b818101518382015260200161341e565b906020916134568151809281855285808601910161341c565b601f01601f1916010190565b600435906001600160a01b0382168203612d5157565b602435906001600160a01b0382168203612d5157565b35906001600160a01b0382168203612d5157565b6060906003190112612d51576004356001600160a01b0381168103612d5157906024356001600160a01b0381168103612d51579060443590565b9181601f84011215612d515782359167ffffffffffffffff8311612d51576020808501948460051b010111612d5157565b90602080835192838152019201905f5b81811061352a5750505090565b825180516001600160801b0316855260209081015164ffffffffff16818601526040909401939092019160010161351d565b35908115158203612d5157565b610120810190811067ffffffffffffffff82111761358657604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761358657604052565b610180810190811067ffffffffffffffff82111761358657604052565b6060810190811067ffffffffffffffff82111761358657604052565b90601f8019910116810190811067ffffffffffffffff82111761358657604052565b67ffffffffffffffff811161358657601f01601f191660200190565b35906001600160801b0382168203612d5157565b61364a81613bc6565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161368357565b634e487b7160e01b5f52601160045260245ffd5b91906001600160a01b031680156138c957815f5260036020526001600160a01b0360405f2054161515806138c1575b806138a4575b613891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836137dc575b6001600160a01b039350856137a5575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361378d57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b6137c4825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561372c565b919290508061383a575b156137f35782829161371c565b828461380b57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613868575b806137e65750825f526005602052336001600160a01b0360405f205416146137e6565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613845565b50630da9b01360e01b5f5260045260245ffd5b50815f52600960205260ff600160405f20015460b01c16156136cc565b5060016136c6565b633250574960e11b5f525f60045260245ffd5b359064ffffffffff82168203612d5157565b67ffffffffffffffff81116135865760051b60200190565b9190826040910312612d515760405161391e8161359a565b602061393781839561392f8161362d565b8552016138dc565b910152565b9190826040910312612d51576040516139548161359a565b60208082946139628161348e565b84520135910152565b919081101561397b5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b0381168103612d515790565b604051906139b08261359a565b5f6020838281520152565b9081546139c7816138ee565b926139d560405194856135ef565b81845260208401905f5260205f205f915b8383106139f35750505050565b600160208192604051613a058161359a565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906139e6565b90604051613a3c816135d3565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b0381168103612d515790565b358015158103612d515790565b90613a8e838284613697565b803b613a9b575b50505050565b602091613ae16001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061343d565b03815f865af15f9181613b69575b50613b1d5750613afd61470a565b80519081613b185782633250574960e11b5f5260045260245ffd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000630a85bd0160e11b911603613b5757505f808080613a95565b633250574960e11b5f5260045260245ffd5b9091506020813d602011613bbe575b81613b85602093836135ef565b81010312612d5157517fffffffff0000000000000000000000000000000000000000000000000000000081168103612d5157905f613aef565b3d9150613b78565b805f5260036020526001600160a01b0360405f205416908115613be7575090565b637e27328960e01b5f5260045260245ffd5b80511561397b5760200190565b805182101561397b5760209160051b010190565b9064ffffffffff421691805f52600a602052613c3860405f206139bb565b908364ffffffffff6020613c4b85613bf9565b5101511611613cfa57805f5260096020528364ffffffffff60405f205460c81c161115613cdb57506001600160801b03613c8482613bf9565b515116916001925b8251841015613cd4578464ffffffffff6020613ca88787613c06565b5101511611613cd4576001600160801b0360019181613cc78787613c06565b5151160116930192613c8c565b9350915050565b919250505f5260096020526001600160801b03600260405f2001541690565b505f925050565b805f52600960205260ff600160405f20015460a01c165f14613d235750600490565b805f52600960205260405f205460f81c613d8f57805f52600960205264ffffffffff60405f205460a01c164210613d8a57613d5d81613c1a565b905f5260096020526001600160801b0380600260405f200154169116105f14613d8557600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ecf575b80613eb2575b613ea0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613e69575b1680613e51575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613e0d565b613e88835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613e06565b630da9b01360e01b5f5260045260245ffd5b50805f52600960205260ff600160405f20015460b01c1615613dba565b506001600160a01b0382161515613db4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613f1357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613f5d6001600160801b03604084015116602061010085015101519061477f565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156145ec5780156145c4578151801561459c577f00000000000000000000000000000000000000000000000000000000000000008111614571575064ffffffffff6020613fcb84613bf9565b5101511681101561452d57505f905f905f81515f905b8082106144a5575050505064ffffffffff804216911690818110156144775750506001600160801b03169081810361444957505060075493845f52600960205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206141ad8751975f19890190613c06565b51015160c81b169360a01b169116171785555f5b818110614397575050600187016007556001600160a01b0360208301511680156138c9576141f7886001600160a01b0392613d95565b1661436b5786826142456001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061485c565b6001600160801b036020840151168061433b575b506001600160a01b03815116946143306143126001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142b78b61359a565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061350d565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614365906001600160a01b036060840151166001600160a01b03610100850151511690339061485c565b5f614259565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600a60205260405f20906143b28160e0870151613c06565b5182549268010000000000000000841015613586576001840180825584101561397b576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016141c1565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b91935091936144c9906001600160801b036144c08588613c06565b5151169061475f565b9364ffffffffff8060206144dd8685613c06565b510151169416808511156144f957506001849301909291613fe1565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061453e84613bf9565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561465a575b508115614641575090565b90506001600160a01b036146553392613641565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614636565b805f52600960205261469d600260405f2001613a2f565b90805f52600960205260ff600160405f20015460a01c165f146146cb5750602001516001600160801b031690565b90815f52600960205260405f205460f81c6146ed57506146ea90613c1a565b90565b6146ea91506001600160801b036040818351169201511690613663565b3d15614734573d9061471b82613611565b9161472960405193846135ef565b82523d5f602084013e565b606090565b6146ea9061474681614686565b905f526009602052600260405f20015460801c90613663565b906001600160801b03809116911601906001600160801b03821161368357565b91909160405161478e8161359a565b5f81525f6020820152926001600160801b03821690811561483f5767016345785d8a00008111614808576147ca6001600160801b03918361499b565b16602085019181835211156147f4576001600160801b0391826147ef92511690613663565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516148508161359a565b5f81525f602082015290565b9091926001600160a01b036148bb9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148b66084836135ef565b61490d565b565b6148bb926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148b66064836135ef565b5f806001600160a01b0361493693169360208151910182865af161492f61470a565b9083614a49565b8051908115159182614977575b505061494c5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8192509060209181010312612d515760200151801590811503612d51575f80614943565b9091905f1983820983820291828083109203918083039214614a3857670de0b6b3a7640000821015614a08577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614a865750805115614a5e57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614acc575b614a97575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15614a8f56fea164736f6c634300081a000a"; + hex"60c0604052346103e457614da86060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600160075561499a908161040e823960805181613dac015260a051818181612f330152613e550152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461329f57508063027b67441461327d57806306fdde03146131c2578063081812fc146131a4578063095ea7b31461309f5780631400ecec14612fee5780631c1cdd4c14612f8a5780631e99d56914612f6d57806323b872dd14612f565780632fe4304114612f1c578063303acc8514612edf57806332fbe22b14612d82578063406887cb14612c1057806340e58ee514612958578063425d30dd1461290857806342842e0e146128df57806342966c681461271b57806344267570146126f55780634857501f146126845780634869e12d1461264a5780634cc55e111461229157806357404b12146122035780636352211e146121d45780636d0cee75146121d457806370a082311461216a57806375829def146120fc5780637cad6cd11461200b5780637de6b1db14611ebe5780637f5799f914611e655780638659c27014611aae578063894e9a0d1461176f578063897f362b146114a45780638f69b993146114245780639067b677146113d557806395d89b41146112cd578063a22cb46514611219578063a80fc071146111c8578063ad35efd414611169578063b256456914611119578063b88d4fde1461108f578063b8a3be661461105a578063b971302a1461100c578063bc2be1be14610fbd578063c156a11d14610bc9578063c87b56dd14610abe578063d4dbd20b14610a6d578063d511609f14610a22578063d975dfed146109d7578063e985e9c51461097e578063ea5ead19146106a9578063eac8f5b814610658578063f590c176146105fd578063f851a440146105d85763fdd46d601461026e575f80fd5b346105d45760603660031901126105d45760043561028a6133cc565b90604435916001600160801b038316908184036105d4576102a9613da2565b825f52600a60205260ff600160405f20015460a81c16156105c257825f52600a60205260ff600160405f20015460a01c166105af576001600160a01b03811690811561059c57821561058957835f5260036020526001600160a01b0360405f205416948583141580610579575b61055e576001600160801b0361032b866145fa565b16808511610544575061035090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a90613948565b6001600160801b036103ae81602084015116928260408183511692015116906135a3565b161115610512575b835f52600a6020526103da836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104fc575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916104c2575b50160361049757005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104e4915060203d6020116104ea575b6104dc818361352f565b810190613a8b565b5f61048e565b503d6104d2565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b50610583856144d5565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d4575f3660031901126105d45760206001600160a01b035f5416604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d45760403660031901126105d4576004356106c56133cc565b906106cf816145fa565b916106d8613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959576001600160a01b0381168015610946576001600160801b03841691821561058957835f5260036020526001600160a01b0360405f205416948583141580610936575b61055e576001600160801b03610764866145fa565b16808511610544575061078990855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107c390613948565b6001600160801b036107e781602084015116928260408183511692015116906135a3565b161115610904575b835f52600a602052610813836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806108ee575b61087957005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916108cf5750160361049757005b6108e8915060203d6020116104ea576104dc818361352f565b8461048e565b50835f52600960205260ff60405f205416610873565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107ef565b50610940856144d5565b1561074f565b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105d45760403660031901126105d4576109976133b6565b6001600160a01b036109a76133cc565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a116020916145fa565b6001600160801b0360405191168152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a6020526020600260405f20015460801c604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d45760203660031901126105d457600435610adb81613aab565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f1575f90610b4c575b610b4890604051918291602083526020830190613391565b0390f35b503d805f833e610b5c818361352f565b8101906020818303126105d45780519067ffffffffffffffff82116105d457019080601f830112156105d457815191610b9483613551565b91610ba2604051938461352f565b838352602084830101116105d457610b4892610bc49160208085019101613370565b610b30565b346105d45760403660031901126105d457600435610be56133cc565b90610bee613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f5260036020526001600160a01b0360405f20541691823303610fa657610c30826145fa565b6001600160801b03811680158015610cce575b5050506001600160a01b03811615610cbb57610c67826001600160a01b0392613c68565b169182610c815750637e27328960e01b5f5260045260245ffd5b808303610c8a57005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cd6613da2565b845f52600a60205260ff600160405f20015460a81c1615610f9457845f52600a60205260ff600160405f20015460a01c16610f81578515610f6e5761058957835f5260036020526001600160a01b0360405f205416918286141580610f5e575b610f43576001600160801b03610d4b866145fa565b16808311610f295750610d7090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610daa90613948565b6001600160801b03610dce81602084015116928260408183511692015116906135a3565b161115610ef7575b835f52600a6020526001600160a01b03600160405f20015416610dfa82878361477e565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610ee1575b610e65575b80610c43565b604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91610ec2575b5016036104975780610e5f565b610edb915060203d6020116104ea576104dc818361352f565b87610eb5565b50815f52600960205260ff60405f205416610e5a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610dd6565b828663287ecaef60e21b5f5260045260245260445260645ffd5b858563b34359d360e01b5f526004523360245260445260645ffd5b50610f68856144d5565b15610d36565b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d45760203660031901126105d4576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d45760803660031901126105d4576110a86133b6565b6110b06133cc565b6064359167ffffffffffffffff83116105d457366023840112156105d4578260040135916110dd83613551565b926110eb604051948561352f565b80845236602482870101116105d4576020815f926024611117980183880137850101526044359161399b565b005b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576111a190613bd4565b60405160058210156111b4576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d45760403660031901126105d4576112326133b6565b602435908115158092036105d4576001600160a01b03169081156112a157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4575f3660031901126105d4576040515f6002548060011c906001811680156113cb575b6020831081146113b7578285529081156113935750600114611335575b610b48836113218185038261352f565b604051918291602083526020830190613391565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061137957509091508101602001611321611311565b919260018160209254838588010152019101909291611361565b60ff191660208086019190915291151560051b840190910191506113219050611311565b634e487b7160e01b5f52602260045260245ffd5b91607f16916112f4565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c16156106475761145c90613bd4565b6005811015806111b45760028214908115611498575b8115611486575b6020826040519015158152f35b90506111b45760046020911482611479565b5050600381145f611472565b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d4578036036101206003198201126105d4576114df613da2565b60c482013590602219018112156105d45781019060048201359167ffffffffffffffff83116105d45760248101908360061b80360383136105d4576004602091611528876137ef565b96611536604051988961352f565b875282870193010101913683116105d457905b8282106117555750505081519161155f836137ef565b9261156d604051948561352f565b808452601f1961157c826137ef565b015f5b81811061173257505064ffffffffff4216916001600160801b036115a282613acc565b51511664ffffffffff8060206115b785613acc565b51015116850116604051916115cb836134da565b825260208201526115db86613acc565b526115e585613acc565b5060015b8281106116bd575050506115ff8260040161397a565b9261160c6024840161397a565b92611619604482016138a8565b916064820135936001600160a01b0385168095036105d4576020966116b596611675966001600160801b036116aa976001600160a01b0361165c60848a0161398e565b948161166a60a48c0161398e565b976040519d8e6134bd565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161383d565b610100820152613dfc565b604051908152f35b806001600160801b036116d260019385613ad9565b51511664ffffffffff8060206116eb5f1986018c613ad9565b510151168160206116fc8689613ad9565b5101511601166040519161170f836134da565b825260208201526117208289613ad9565b5261172b8188613ad9565b50016115e9565b602090604051611741816134da565b5f81525f838201528282890101520161157f565b60206040916117643685613807565b815201910190611549565b346105d45760203660031901126105d4576004356060610160604051611794816134f6565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201526040516117da81613513565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611a9a576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b03851687526118d7600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c161515885201613948565b6101208b019081526118e889613bd4565b60058110156111b457600214611a92575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119678c6134f6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b019889526119bb906138d4565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b4891613461565b5f87526118f9565b634e487b7160e01b5f52604160045260245ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d457611adf903690600401613430565b90611ae8613da2565b5f915b808310611af457005b611aff838284613884565b3592611b09613da2565b835f52600a60205260ff600160405f20015460a81c1615611e5357835f52600a60205260ff600160405f20015460a01c165f14611b535783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611e4157611b88815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57611b9681613aed565b90805f52600a602052611bae600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081611c029481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611de0575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d146001600160a01b03600160405f2001541694611cec88858861477e565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611d65575b50505050506001019190611aeb565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f91611dc2575b5016036104975780808080611d56565b611dda915060203d81116104ea576104dc818361352f565b87611db2565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611c4c565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600b602052610b48611eaa60405f206138d4565b604051918291602083526020830190613461565b346105d45760203660031901126105d457600435611eda613da2565b805f52600a60205260ff600160405f20015460a81c161561064757611efe81613bd4565b60058110156111b45760048103611f225750634a5541ef60e01b5f5260045260245ffd5b60038103611f3d575063fe19f19f60e01b5f5260045260245ffd5b600214611ff957611f62815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57805f52600a60205260ff60405f205460f01c1615611fe7576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d45760203660031901126105d4576004356001600160a01b0381168091036105d4576001600160a01b035f54163381036120e6575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120d25760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d4576121156133b6565b5f546001600160a01b0381163381036120e657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d45760203660031901126105d4576001600160a01b0361218b6133b6565b1680156121a8575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d45760203660031901126105d45760206121f2600435613aab565b6001600160a01b0360405191168152f35b346105d45760203660031901126105d45760043561221f6138bc565b50805f52600a60205260ff600160405f20015460a81c1615610647575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c16612269836134da565b8252602082015261228f8251809264ffffffffff60208092828151168552015116910152565bf35b346105d45760403660031901126105d45760043567ffffffffffffffff81116105d4576122c2903690600401613430565b9060243567ffffffffffffffff81116105d4576122e3903690600401613430565b9190926122ee613da2565b82810361261a575f5b81811061230057005b61230b818385613884565b35612317828486613884565b355f5260036020526001600160a01b0360405f2054169061234161233c84888a613884565b6138a8565b9161234a613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959578015612607576001600160801b0383169081156125f457825f5260036020526001600160a01b0360405f2054169384821415806125e4575b6125c9576001600160801b036123cc856145fa565b168084116125af57506123f190845f52600a602052600260405f20015460801c614620565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561242b90613948565b6001600160801b0361244f81602084015116928260408183511692015116906135a3565b16111561257d575b825f52600a6020526001600160a01b03600160405f2001541661247b83838361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612567575b6124ec575b505050506001016122f7565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91612549575b501603610497578080806124e0565b612561915060203d81116104ea576104dc818361352f565b8961253a565b50835f52600960205260ff60405f2054166124db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612457565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506125ee846144d5565b156123b7565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a11602091614547565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f6126bd82613bd4565b60058110156111b4576002036126db575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126ce565b346105d4575f3660031901126105d45760206001600160a01b0360085416604051908152f35b346105d45760203660031901126105d457600435612737613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c16156128b457612776816144d5565b15611e2b57805f5260036020526001600160a01b0360405f2054161515806128ad575b80612890575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612847575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061283557005b637e27328960e01b5f5260045260245ffd5b612866835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f1981540190556127ed565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561279f565b505f612799565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4576111176128f0366133f6565b906040519261290060208561352f565b5f845261399b565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d45760203660031901126105d457600435612974613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c165f146129bd57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611e41576129ef815f52600a6020526001600160a01b0360405f205416331490565b15611e2b576129fd81613aed565b90805f52600a602052612a15600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081612a699481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612beb575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b536001600160a01b03600160405f2001541694611cec88858861477e565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b9657005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f916108cf5750160361049757005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ab3565b346105d45760203660031901126105d457612c296133b6565b6001600160a01b035f541690338203612d6b57806001600160a01b03913b15612d3f57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f1575f91612d10575b5015612ce5576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d32915060203d602011612d38575b612d2a818361352f565b81019061386c565b82612c97565b503d612d20565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d45761014060031982360301126105d457612dbc613da2565b604051612dc8816134bd565b612dd4826004016133e2565b8152612de2602483016133e2565b6020820152612df36044830161356d565b604082015260648201356001600160a01b03811681036105d4576060820152612e1e608483016134b0565b6080820152612e2f60a483016134b0565b60a0820152612e4060c483016137dd565b60c082015260e482013567ffffffffffffffff81116105d457820191366023840112156105d457600483013592612e76846137ef565b90612e84604051928361352f565b848252602060048184019660061b83010101903682116105d457602401945b818610612ec55760206116b5866116aa878760e084015261010436910161383d565b6020604091612ed43689613807565b815201950194612ea3565b346105d45760203660031901126105d4576001600160a01b03612f006133b6565b165f526009602052602060ff60405f2054166040519015158152f35b346105d4575f3660031901126105d45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105d457611117612f67366133f6565b916135c3565b346105d4575f3660031901126105d4576020600754604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757612fc290613bd4565b60058110156111b4578060209115908115612fe3575b506040519015158152f35b600191501482612fd8565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576020905f90805f52600a835260ff60405f205460f01c1680613083575b613051575b506001600160801b0360405191168152f35b61307d9150805f52600a83526130776001600160801b03600260405f2001541691613aed565b906135a3565b8261303f565b50805f52600a835260ff600160405f20015460a01c161561303a565b346105d45760403660031901126105d4576130b86133b6565b6024356130c481613aab565b33151580613191575b8061315e575b6131325781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156130d3565b50336001600160a01b03821614156130cd565b346105d45760203660031901126105d45760206121f2600435613581565b346105d4575f3660031901126105d4576040515f6001548060011c90600181168015613273575b6020831081146113b757828552908115611393575060011461321557610b48836113218185038261352f565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061325957509091508101602001611321611311565b919260018160209254838588010152019101909291613241565b91607f16916131e9565b346105d4575f3660031901126105d457602060405167016345785d8a00008152f35b346105d45760203660031901126105d457600435906001600160e01b031982168092036105d457817f4906490600000000000000000000000000000000000000000000000000000000602093149081156132fb575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613346575b8115613335575b50836132f4565b6301ffc9a760e01b9150148361332e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613327565b5f5b8381106133815750505f910152565b8181015183820152602001613372565b906020916133aa81518092818552858086019101613370565b601f01601f1916010190565b600435906001600160a01b03821682036105d457565b602435906001600160a01b03821682036105d457565b35906001600160a01b03821682036105d457565b60609060031901126105d4576004356001600160a01b03811681036105d457906024356001600160a01b03811681036105d4579060443590565b9181601f840112156105d45782359167ffffffffffffffff83116105d4576020808501948460051b0101116105d457565b90602080835192838152019201905f5b81811061347e5750505090565b825180516001600160801b0316855260209081015164ffffffffff168186015260409094019390920191600101613471565b359081151582036105d457565b610120810190811067ffffffffffffffff821117611a9a57604052565b6040810190811067ffffffffffffffff821117611a9a57604052565b610180810190811067ffffffffffffffff821117611a9a57604052565b6060810190811067ffffffffffffffff821117611a9a57604052565b90601f8019910116810190811067ffffffffffffffff821117611a9a57604052565b67ffffffffffffffff8111611a9a57601f01601f191660200190565b35906001600160801b03821682036105d457565b61358a81613aab565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116120d257565b91906001600160a01b03168015610cbb57815f5260036020526001600160a01b0360405f2054161515806137d5575b806137b8575b6137a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836136f0575b6001600160a01b039350856136b9575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8a57505050565b6136d8825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613658565b919290508061374e575b1561370757828291613648565b828461371f57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b50338414801561377c575b806136fa5750825f526005602052336001600160a01b0360405f205416146136fa565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613759565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156135f8565b5060016135f2565b359064ffffffffff821682036105d457565b67ffffffffffffffff8111611a9a5760051b60200190565b91908260409103126105d45760405161381f816134da565b60206138388183956138308161356d565b8552016137dd565b910152565b91908260409103126105d457604051613855816134da565b6020808294613863816133e2565b84520135910152565b908160209103126105d4575180151581036105d45790565b91908110156138945760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105d45790565b604051906138c9826134da565b5f6020838281520152565b9081546138e0816137ef565b926138ee604051948561352f565b81845260208401905f5260205f205f915b83831061390c5750505050565b60016020819260405161391e816134da565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906138ff565b9060405161395581613513565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105d45790565b3580151581036105d45790565b906139a78382846135c3565b803b6139b4575b50505050565b6020916139fa6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613391565b03815f865af15f9181613a6a575b50613a365750613a166145cb565b80519081613a315782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613a5857505f8080806139ae565b633250574960e11b5f5260045260245ffd5b613a8491925060203d6020116104ea576104dc818361352f565b905f613a08565b908160209103126105d457516001600160e01b0319811681036105d45790565b805f5260036020526001600160a01b0360405f205416908115612835575090565b8051156138945760200190565b80518210156138945760209160051b010190565b9064ffffffffff421691805f52600b602052613b0b60405f206138d4565b908364ffffffffff6020613b1e85613acc565b5101511611613bcd57805f52600a6020528364ffffffffff60405f205460c81c161115613bae57506001600160801b03613b5782613acc565b515116916001925b8251841015613ba7578464ffffffffff6020613b7b8787613ad9565b5101511611613ba7576001600160801b0360019181613b9a8787613ad9565b5151160116930192613b5f565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613bf65750600490565b805f52600a60205260405f205460f81c613c6257805f52600a60205264ffffffffff60405f205460a01c164210613c5d57613c3081613aed565b905f52600a6020526001600160801b0380600260405f200154169116105f14613c5857600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613d90575b80613d73575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613d3c575b1680613d24575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613ce0565b613d5b835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613cd9565b50805f52600a60205260ff600160405f20015460b01c1615613c8d565b506001600160a01b0382161515613c87565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dd457565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613e1e6001600160801b036040840151166020610100850151015190614640565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156144ad578015614485578151801561445d577f00000000000000000000000000000000000000000000000000000000000000008111614432575064ffffffffff6020613e8c84613acc565b510151168110156143ee57505f905f905f81515f905b808210614366575050505064ffffffffff804216911690818110156143385750506001600160801b03169081810361430a57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406e8751975f19890190613ad9565b51015160c81b169360a01b169116171785555f5b818110614258575050600187016007556001600160a01b036020830151168015610cbb576140b8886001600160a01b0392613c68565b1661422c5786826141066001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061471d565b6001600160801b03602084015116806141fc575b506001600160a01b03815116946141f16141d36001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141788b6134da565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190613461565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614226906001600160a01b036060840151166001600160a01b03610100850151511690339061471d565b5f61411a565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142738160e0870151613ad9565b5182549268010000000000000000841015611a9a5760018401808255841015613894576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614082565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919350919361438a906001600160801b036143818588613ad9565b51511690614620565b9364ffffffffff80602061439e8685613ad9565b510151169416808511156143ba57506001849301909291613ea2565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff60206143ff84613acc565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561451b575b508115614502575090565b90506001600160a01b036145163392613581565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6144f7565b805f52600a60205261455e600260405f2001613948565b90805f52600a60205260ff600160405f20015460a01c165f1461458c5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6145ae57506145ab90613aed565b90565b6145ab91506001600160801b0360408183511692015116906135a3565b3d156145f5573d906145dc82613551565b916145ea604051938461352f565b82523d5f602084013e565b606090565b6145ab9061460781614547565b905f52600a602052600260405f20015460801c906135a3565b906001600160801b03809116911601906001600160801b0382116120d257565b91909160405161464f816134da565b5f81525f6020820152926001600160801b0382169081156147005767016345785d8a000081116146c95761468b6001600160801b039183614853565b16602085019181835211156146b5576001600160801b0391826146b0925116906135a3565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614711816134da565b5f81525f602082015290565b9091926001600160a01b0361477c9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261477760848361352f565b6147ce565b565b61477c926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261477760648361352f565b5f806001600160a01b036147f793169360208151910182865af16147f06145cb565b9083614901565b8051908115159182614838575b505061480d5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61484b925060208091830101910161386c565b155f80614804565b9091905f19838209838202918280831092039180830392146148f057670de0b6b3a76400008210156148c0577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061493e575080511561491657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614984575b61494f575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561494756fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; @@ -182,12 +182,7 @@ contract Precompiles { ); } - /// @notice Deploys all V2 Core contracts in the following order: - /// - /// 1. {SablierV2NFTDescriptor} - /// 2. {SablierV2LockupDynamic} - /// 3. {SablierV2LockupLinear} - /// 4. {SablierV2LockupTranched} + /// @notice Deploys all V2 Core contracts. function deployCore(address initialAdmin) public returns ( diff --git a/script/Base.s.sol b/script/Base.s.sol index 647a17c20..35cb9c755 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -87,48 +87,48 @@ contract BaseScript is Script { // forgefmt: disable-start // Arbitrum chain ID - segmentCountMap[42161] = 1170; - trancheCountMap[42161] = 1210; + segmentCountMap[42161] = 1160; + trancheCountMap[42161] = 1200; // Avalanche chain ID. - segmentCountMap[43114] = 530; + segmentCountMap[43114] = 520; trancheCountMap[43114] = 540; // Base chain ID. - segmentCountMap[8453] = 2200; - trancheCountMap[8453] = 2290; + segmentCountMap[8453] = 2170; + trancheCountMap[8453] = 2270; // Blast chain ID. - segmentCountMap[238] = 1100; - trancheCountMap[238] = 1130; + segmentCountMap[238] = 1080; + trancheCountMap[238] = 1120; // BNB chain ID. - segmentCountMap[56] = 4870; - trancheCountMap[56] = 5180; + segmentCountMap[56] = 4820; + trancheCountMap[56] = 5130; // Ethereum chain ID. - segmentCountMap[1] = 1100; - trancheCountMap[1] = 1130; + segmentCountMap[1] = 1080; + trancheCountMap[1] = 1120; // Gnosis chain ID. - segmentCountMap[100] = 610; + segmentCountMap[100] = 600; trancheCountMap[100] = 620; // Optimism chain ID. - segmentCountMap[10] = 1100; - trancheCountMap[10] = 1130; + segmentCountMap[10] = 1080; + trancheCountMap[10] = 1120; // Polygon chain ID. - segmentCountMap[137] = 1100; - trancheCountMap[137] = 1130; + segmentCountMap[137] = 1080; + trancheCountMap[137] = 1120; // Scroll chain ID. - segmentCountMap[534352] = 340; - trancheCountMap[534352] = 350; + segmentCountMap[534352] = 330; + trancheCountMap[534352] = 340; // Sepolia chain ID. - segmentCountMap[11155111] = 1100; - trancheCountMap[11155111] = 1130; + segmentCountMap[11155111] = 1080; + trancheCountMap[11155111] = 1120; // forgefmt: disable-end } diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index 36deb6db5..df6239c8a 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -8,14 +8,8 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys all V2 Core contract in the following order: -/// -/// 1. {SablierV2NFTDescriptor} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} +/// @notice Deploys all V2 Core contracts. contract DeployCore is BaseScript { - /// @dev Deploy via Forge. function run(address initialAdmin) public virtual diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index 0bcf8b416..a8059dabc 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -8,13 +8,7 @@ import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys these contracts in the following order: -/// -/// 1. {SablierV2LockupDynamic} -/// 2. {SablierV2LockupLinear} -/// 3. {SablierV2LockupTranched} contract DeployCore2 is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index cf943cf2a..b65be9ae7 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -8,16 +8,9 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys all V2 Core contracts at deterministic addresses across chains, in the following order: -/// -/// 1. {SablierV2NFTDescriptor} -/// 2. {SablierV2LockupDynamic} -/// 3. {SablierV2LockupLinear} -/// 4. {SablierV2LockupTranched} -/// +/// @notice Deploys all V2 Core contracts at deterministic addresses across chains. /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - /// @dev Deploy via Forge. function run(address initialAdmin) public virtual diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index cab3694f3..7b50fb75d 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -8,15 +8,8 @@ import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys these contracts at deterministic addresses across chains, in the following order: -/// -/// 1. {SablierV2LockupDynamic} -/// 2. {SablierV2LockupLinear} -/// 3. {SablierV2LockupTranched} -/// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor nftDescriptor diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 799233f41..512f89223 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -9,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index c3671bd1d..de36726ab 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -9,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index e06636209..9e2641c99 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -9,7 +9,6 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupTranched is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index 53252adeb..f7a72bff2 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -8,7 +8,6 @@ import { BaseScript } from "./Base.s.sol"; /// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { - /// @dev Deploy via Forge. function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { bytes32 salt = constructCreate2Salt(); nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index 154215b9f..ae5a9a7cc 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -7,7 +7,6 @@ import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupDynamic is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index 8f666c70e..940966a2f 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -7,7 +7,6 @@ import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupLinear is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index 76d1ccadd..adae8f7fe 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -7,7 +7,6 @@ import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployLockupTranched is BaseScript { - /// @dev Deploy via Forge. function run( address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index e6ec770f7..6f3019171 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.s.sol @@ -6,7 +6,6 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; contract DeployNFTDescriptor is BaseScript { - /// @dev Deploy via Forge. function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { nftDescriptor = new SablierV2NFTDescriptor(); } diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index ca30ca1c0..5aa4f6ab5 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -16,7 +16,6 @@ mkdir $artifacts \ "$artifacts/interfaces" \ "$artifacts/interfaces/erc20" \ "$artifacts/interfaces/erc721" \ - "$artifacts/interfaces/hooks" \ "$artifacts/libraries" # Generate the artifacts with Forge @@ -29,6 +28,7 @@ cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $artif cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $artifacts interfaces=./artifacts/interfaces +cp out-optimized/ISablierLockupRecipient.sol/ISablierLockupRecipient.json $interfaces cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $interfaces cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $interfaces cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $interfaces @@ -42,10 +42,6 @@ erc721=./artifacts/interfaces/erc721 cp out-optimized/IERC721.sol/IERC721.json $erc721 cp out-optimized/IERC721Metadata.sol/IERC721Metadata.json $erc721 -hooks=./artifacts/interfaces/hooks -cp out-optimized/ISablierV2Recipient.sol/ISablierV2Recipient.json $hooks -cp out-optimized/ISablierV2Sender.sol/ISablierV2Sender.json $hooks - libraries=./artifacts/libraries cp out-optimized/Errors.sol/Errors.json $libraries diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol index ebe8f2002..b06b15c64 100644 --- a/src/SablierV2LockupDynamic.sol +++ b/src/SablierV2LockupDynamic.sol @@ -262,7 +262,7 @@ contract SablierV2LockupDynamic is SD59x18 segmentStreamedAmount = multiplier.mul(currentSegmentAmount); // Although the segment streamed amount should never exceed the total segment amount, this condition is - // checked without asserting to avoid locking funds in case of a bug. If this situation occurs, the + // checked without asserting to avoid locking assets in case of a bug. If this situation occurs, the // amount streamed in the segment is considered zero (except for past withdrawals), and the segment is // effectively voided. if (segmentStreamedAmount.gt(currentSegmentAmount)) { @@ -297,7 +297,7 @@ contract SablierV2LockupDynamic is SD59x18 streamedAmount = multiplier.mul(depositedAmount); // Although the streamed amount should never exceed the deposited amount, this condition is checked - // without asserting to avoid locking funds in case of a bug. If this situation occurs, the withdrawn + // without asserting to avoid locking assets in case of a bug. If this situation occurs, the withdrawn // amount is considered to be the streamed amount, and the stream is effectively frozen. if (streamedAmount.gt(depositedAmount)) { return _streams[streamId].amounts.withdrawn; diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 5d448b048..2b8724d0a 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -219,7 +219,7 @@ contract SablierV2LockupLinear is UD60x18 streamedAmount = elapsedTimePercentage.mul(depositedAmount); // Although the streamed amount should never exceed the deposited amount, this condition is checked - // without asserting to avoid locking funds in case of a bug. If this situation occurs, the withdrawn + // without asserting to avoid locking assets in case of a bug. If this situation occurs, the withdrawn // amount is considered to be the streamed amount, and the stream is effectively frozen. if (streamedAmount.gt(depositedAmount)) { return _streams[streamId].amounts.withdrawn; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 7a2ad5c91..654c2deac 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -8,8 +8,7 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2Recipient } from "../interfaces/hooks/ISablierV2Recipient.sol"; -import { ISablierV2Sender } from "../interfaces/hooks/ISablierV2Sender.sol"; +import { ISablierLockupRecipient } from "../interfaces/ISablierLockupRecipient.sol"; import { ISablierV2Lockup } from "../interfaces/ISablierV2Lockup.sol"; import { ISablierV2NFTDescriptor } from "../interfaces/ISablierV2NFTDescriptor.sol"; import { Errors } from "../libraries/Errors.sol"; @@ -40,6 +39,9 @@ abstract contract SablierV2Lockup is /// @inheritdoc ISablierV2Lockup ISablierV2NFTDescriptor public override nftDescriptor; + /// @dev Mapping of contracts allowed to hook to Sablier when a stream is canceled or when assets are withdrawn. + mapping(address recipient => bool allowed) internal _allowedToHook; + /// @dev Sablier V2 Lockup streams mapped by unsigned integers. mapping(uint256 id => Lockup.Stream stream) internal _streams; @@ -131,6 +133,11 @@ abstract contract SablierV2Lockup is withdrawnAmount = _streams[streamId].amounts.withdrawn; } + /// @inheritdoc ISablierV2Lockup + function isAllowedToHook(address recipient) external view returns (bool result) { + result = _allowedToHook[recipient]; + } + /// @inheritdoc ISablierV2Lockup function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result) { if (_statusOf(streamId) != Lockup.Status.SETTLED) { @@ -233,6 +240,26 @@ abstract contract SablierV2Lockup is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierV2Lockup + function allowToHook(address recipient) external override onlyAdmin { + // Check: non-zero code size. + if (recipient.code.length == 0) { + revert Errors.SablierV2Lockup_AllowToHookZeroCodeSize(recipient); + } + + // Check: recipients implements the ERC-165 interface ID required by {ISablierLockupRecipient}. + bytes4 interfaceId = type(ISablierLockupRecipient).interfaceId; + if (!ISablierLockupRecipient(recipient).supportsInterface(interfaceId)) { + revert Errors.SablierV2Lockup_AllowToHookUnsupportedInterface(recipient); + } + + // Effect: put the recipient on the allowlist. + _allowedToHook[recipient] = true; + + // Log the allowlist addition. + emit ISablierV2Lockup.AllowToHook({ admin: msg.sender, recipient: recipient }); + } + /// @inheritdoc ISablierV2Lockup function burn(uint256 streamId) external override noDelegateCall notNull(streamId) { // Check: only depleted streams can be burned. @@ -304,13 +331,6 @@ abstract contract SablierV2Lockup is // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); - - // Interaction: 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 ISablierV2Recipient(recipient).onLockupStreamRenounced(streamId) { } catch { } - } } /// @inheritdoc ISablierV2Lockup @@ -362,37 +382,25 @@ abstract contract SablierV2Lockup is revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount); } - // Retrieve the sender from storage. - address sender = _streams[streamId].sender; - // Effects and Interactions: make the withdrawal. _withdraw(streamId, to, amount); // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); - // Interaction: 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 ISablierV2Recipient(recipient).onLockupStreamWithdrawn({ + // Interaction: if `msg.sender` is not the recipient and the recipient is on the allowlist, run the hook. + if (msg.sender != recipient && _allowedToHook[recipient]) { + bytes4 selector = ISablierLockupRecipient(recipient).onSablierLockupWithdraw({ streamId: streamId, caller: msg.sender, to: to, amount: amount - }) { } catch { } - } + }); - // Interaction: if `msg.sender` is not the sender, the sender is a contract and is different from the - // recipient, 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 != sender && sender.code.length > 0 && sender != recipient) { - try ISablierV2Sender(sender).onLockupStreamWithdrawn({ - streamId: streamId, - caller: msg.sender, - to: to, - amount: amount - }) { } catch { } + // Check: the recipient's hook returned the correct selector. + if (selector != ISablierLockupRecipient.onSablierLockupWithdraw.selector) { + revert Errors.SablierV2Lockup_InvalidHookSelector(recipient); + } } } @@ -570,15 +578,19 @@ abstract contract SablierV2Lockup is // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); - // Interaction: 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 ISablierV2Recipient(recipient).onLockupStreamCanceled({ + // Interaction: if the recipient is on the allowlist, run the hook. + if (_allowedToHook[recipient]) { + bytes4 selector = ISablierLockupRecipient(recipient).onSablierLockupCancel({ streamId: streamId, sender: sender, senderAmount: senderAmount, recipientAmount: recipientAmount - }) { } catch { } + }); + + // Check: the recipient's hook returned the correct selector. + if (selector != ISablierLockupRecipient.onSablierLockupCancel.selector) { + revert Errors.SablierV2Lockup_InvalidHookSelector(recipient); + } } } diff --git a/src/interfaces/ISablierLockupRecipient.sol b/src/interfaces/ISablierLockupRecipient.sol new file mode 100644 index 000000000..cf6c80cb3 --- /dev/null +++ b/src/interfaces/ISablierLockupRecipient.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/// @title ISablierLockupRecipient +/// @notice Interface for recipient contracts capable of reacting to cancellations and withdrawals. For this to be able +/// to hook into Sablier, it must fully implement this interface and it must have been allowlisted by the Lockup +/// contract's admin. +/// @dev See {IERC165-supportsInterface}. +/// The implementation MUST implement the {IERC165-supportsInterface} method, which MUST return `true` when called with +/// `0xf8ee98d3`, i.e. `type(ISablierLockupRecipient).interfaceId`. +interface ISablierLockupRecipient is IERC165 { + /// @notice Responds to cancellations. + /// + /// @dev Notes: + /// - The function MUST return the selector `ISablierLockupRecipient.onSablierLockupCancel.selector`. + /// - If this function reverts, the execution in the Lockup contract will revert as well. + /// + /// @param streamId The ID of the canceled stream. + /// @param sender The stream's sender, 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. + /// + /// @return selector The selector of this function needed to validate the hook. + function onSablierLockupCancel( + uint256 streamId, + address sender, + uint128 senderAmount, + uint128 recipientAmount + ) + external + returns (bytes4 selector); + + /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. + /// + /// @dev Notes: + /// - The function MUST return the selector `ISablierLockupRecipient.onSablierLockupWithdraw.selector`. + /// - If this function reverts, the execution in the Lockup contract will revert as well. + /// + /// @param streamId The ID of the stream being withdrawn from. + /// @param caller The original `msg.sender` address that triggered the withdrawal. + /// @param to The address receiving the withdrawn assets. + /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. + /// + /// @return selector The selector of this function needed to validate the hook. + function onSablierLockupWithdraw( + uint256 streamId, + address caller, + address to, + uint128 amount + ) + external + returns (bytes4 selector); +} diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 6616ad569..7701a85c1 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -21,6 +21,11 @@ interface ISablierV2Lockup is EVENTS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Emitted when the admin allows a new recipient contract to hook to Sablier. + /// @param admin The address of the current contract admin. + /// @param recipient The address of the recipient contract put on the allowlist. + event AllowToHook(address admin, address recipient); + /// @notice Emitted when a stream is canceled. /// @param streamId The ID of the stream. /// @param sender The address of the stream's sender. @@ -103,6 +108,11 @@ interface ISablierV2Lockup is /// @param streamId The stream ID for the query. function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount); + /// @notice Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier + /// when a stream is canceled or when assets are withdrawn. + /// @dev See {ISablierLockupRecipient} for more information. + function isAllowedToHook(address recipient) external view returns (bool result); + /// @notice Retrieves a flag indicating whether the stream can be canceled. When the stream is cold, this /// flag is always `false`. /// @dev Reverts if `streamId` references a null stream. @@ -182,6 +192,23 @@ interface ISablierV2Lockup is NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Allows a recipient contract to hook to Sablier when a stream is canceled or when assets are withdrawn. + /// Useful for implementing contracts that hold streams on behalf of users, such as vaults or staking contracts. + /// + /// @dev Emits an {AllowToHook} event. + /// + /// Notes: + /// - Does not revert if the contract is already on the allowlist. + /// - This is an irreversible operation. The contract cannot be removed from the allowlist. + /// + /// Requirements: + /// - `msg.sender` must be the contract admin. + /// - `recipient` must have a non-zero code size. + /// - `recipient` must implement {ISablierLockupRecipient}. + /// + /// @param recipient The address of the contract to allow for hooks. + function allowToHook(address recipient) external; + /// @notice Burns the NFT associated with the stream. /// /// @dev Emits a {Transfer} event. @@ -231,7 +258,6 @@ interface ISablierV2Lockup is /// /// Notes: /// - This is an irreversible operation. - /// - This function attempts to invoke a hook on the stream's recipient, provided that the recipient is a contract. /// /// Requirements: /// - Must not be delegate called. @@ -261,7 +287,6 @@ interface ISablierV2Lockup is /// /// Notes: /// - This function attempts to call a hook on the recipient of the stream, unless `msg.sender` is the recipient. - /// - This function attempts to call a hook on the sender of the stream, unless `msg.sender` is the sender. /// /// Requirements: /// - Must not be delegate called. @@ -313,7 +338,6 @@ interface ISablierV2Lockup is /// /// Notes: /// - This function attempts to call a hook on the recipient of each stream, unless `msg.sender` is the recipient. - /// - This function attempts to call a hook on the sender of each stream, unless `msg.sender` is the sender. /// /// Requirements: /// - Must not be delegate called. diff --git a/src/interfaces/hooks/ISablierV2Recipient.sol b/src/interfaces/hooks/ISablierV2Recipient.sol deleted file mode 100644 index da95fc046..000000000 --- a/src/interfaces/hooks/ISablierV2Recipient.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -/// @title ISablierV2Recipient -/// @notice Interface for recipient contracts capable of reacting to cancellations, renouncements, and withdrawals. -/// @dev Implementation of this interface is optional. If a recipient contract doesn't implement this -/// interface or implements it partially, the function execution will not revert. -interface ISablierV2Recipient { - /// @notice Responds to sender-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 sender The stream's sender, 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 onLockupStreamCanceled( - uint256 streamId, - address sender, - uint128 senderAmount, - uint128 recipientAmount - ) - external; - - /// @notice Responds to renouncements. - /// - /// @dev Notes: - /// - This function may revert, but the Sablier contract will ignore the revert. - /// - /// @param streamId The ID of the renounced stream. - function onLockupStreamRenounced(uint256 streamId) external; - - /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. - /// - /// @dev Notes: - /// - This function may revert, but the Sablier contract will ignore the revert. - /// - /// @param streamId The ID of the stream being withdrawn from. - /// @param caller The original `msg.sender` address that triggered the withdrawal. - /// @param to The address receiving the withdrawn assets. - /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external; -} diff --git a/src/interfaces/hooks/ISablierV2Sender.sol b/src/interfaces/hooks/ISablierV2Sender.sol deleted file mode 100644 index ab8e576ef..000000000 --- a/src/interfaces/hooks/ISablierV2Sender.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -/// @title ISablierV2Sender -/// @notice Interface for sender contracts capable of reacting to withdrawals. -/// @dev Implementation of this interface is optional. If a sender contract doesn't implement this -/// interface, the function execution will not revert. -interface ISablierV2Sender { - /// @notice Responds to withdrawals triggered by any address except the contract implementing this interface. - /// - /// @dev Notes: - /// - This function may revert, but the Sablier contract will ignore the revert. - /// - /// @param streamId The ID of the stream being withdrawn from. - /// @param caller The original `msg.sender` address that triggered the withdrawal. - /// @param to The address receiving the withdrawn assets. - /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external; -} diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index a2899d746..9115a0274 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -21,6 +21,12 @@ library Errors { SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ + /// @notice Thrown when trying to allow for hook a contract that doesn't implement the interface correctly. + error SablierV2Lockup_AllowToHookUnsupportedInterface(address recipient); + + /// @notice Thrown when trying to allow for hook an address with no code. + error SablierV2Lockup_AllowToHookZeroCodeSize(address recipient); + /// @notice Thrown when the broker fee exceeds the maximum allowed fee. error SablierV2Lockup_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxBrokerFee); @@ -30,6 +36,9 @@ library Errors { /// @notice Thrown when trying to create a stream with an end time not in the future. error SablierV2Lockup_EndTimeNotInTheFuture(uint40 blockTimestamp, uint40 endTime); + /// @notice Thrown when the hook does not return the correct selector. + error SablierV2Lockup_InvalidHookSelector(address recipient); + /// @notice Thrown when trying to transfer Stream NFT when transferability is disabled. error SablierV2Lockup_NotTransferable(uint256 tokenId); diff --git a/test/Base.t.sol b/test/Base.t.sol index 1dffc586d..f11fc8ca3 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -15,8 +15,7 @@ import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; import { Noop } from "./mocks/Noop.sol"; -import { GoodRecipient } from "./mocks/hooks/GoodRecipient.sol"; -import { GoodSender } from "./mocks/hooks/GoodSender.sol"; +import { RecipientGood } from "./mocks/Hooks.sol"; import { Assertions } from "./utils/Assertions.sol"; import { Calculations } from "./utils/Calculations.sol"; import { Constants } from "./utils/Constants.sol"; @@ -40,8 +39,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi ERC20Mock internal dai; Defaults internal defaults; - GoodRecipient internal goodRecipient; - GoodSender internal goodSender; + RecipientGood internal recipientGood; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; ISablierV2LockupTranched internal lockupTranched; @@ -56,15 +54,13 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi function setUp() public virtual { // Deploy the base test contracts. dai = new ERC20Mock("Dai Stablecoin", "DAI"); - goodRecipient = new GoodRecipient(); - goodSender = new GoodSender(); + recipientGood = new RecipientGood(); noop = new Noop(); usdt = new ERC20MissingReturn("Tether USD", "USDT", 6); // Label the base test contracts. vm.label({ account: address(dai), newLabel: "DAI" }); - vm.label({ account: address(goodRecipient), newLabel: "Good Recipient" }); - vm.label({ account: address(goodSender), newLabel: "Good Sender" }); + vm.label({ account: address(recipientGood), newLabel: "Good Recipient" }); vm.label({ account: address(noop), newLabel: "Noop" }); vm.label({ account: address(usdt), newLabel: "USDT" }); diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index d90951158..316657fef 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -4,21 +4,26 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/libraries/Errors.sol"; import { Base_Test } from "../Base.t.sol"; -import { ReentrantRecipient } from "../mocks/hooks/ReentrantRecipient.sol"; -import { ReentrantSender } from "../mocks/hooks/ReentrantSender.sol"; -import { RevertingRecipient } from "../mocks/hooks/RevertingRecipient.sol"; -import { RevertingSender } from "../mocks/hooks/RevertingSender.sol"; +import { + RecipientInterfaceIDIncorrect, + RecipientInterfaceIDMissing, + RecipientInvalidSelector, + RecipientReentrant, + RecipientReverting +} from "../mocks/Hooks.sol"; /// @notice Common logic needed by all integration tests, both concrete and fuzz tests. + abstract contract Integration_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ReentrantRecipient internal reentrantRecipient = new ReentrantRecipient(); - ReentrantSender internal reentrantSender = new ReentrantSender(); - RevertingRecipient internal revertingRecipient = new RevertingRecipient(); - RevertingSender internal revertingSender = new RevertingSender(); + RecipientInterfaceIDIncorrect internal recipientInterfaceIDIncorrect = new RecipientInterfaceIDIncorrect(); + RecipientInterfaceIDMissing internal recipientInterfaceIDMissing = new RecipientInterfaceIDMissing(); + RecipientInvalidSelector internal recipientInvalidSelector = new RecipientInvalidSelector(); + RecipientReentrant internal recipientReentrant = new RecipientReentrant(); + RecipientReverting internal recipientReverting = new RecipientReverting(); /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION @@ -40,10 +45,11 @@ abstract contract Integration_Test is Base_Test { /// @dev Labels the most relevant contracts. function labelContracts() internal { - vm.label({ account: address(reentrantRecipient), newLabel: "Reentrant Lockup Recipient" }); - vm.label({ account: address(reentrantSender), newLabel: "Reentrant Lockup Sender" }); - vm.label({ account: address(revertingRecipient), newLabel: "Reverting Lockup Recipient" }); - vm.label({ account: address(revertingSender), newLabel: "Reverting Lockup Sender" }); + vm.label({ account: address(recipientInterfaceIDIncorrect), newLabel: "Recipient Interface ID Incorrect" }); + vm.label({ account: address(recipientInterfaceIDMissing), newLabel: "Recipient Interface ID Missing" }); + vm.label({ account: address(recipientInvalidSelector), newLabel: "Recipient Invalid Selector" }); + vm.label({ account: address(recipientReentrant), newLabel: "Recipient Reentrant" }); + vm.label({ account: address(recipientReverting), newLabel: "Recipient Reverting" }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index b19fbe742..cca53bda0 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -5,6 +5,7 @@ import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; +import { AllowToHook_Integration_Concrete_Test } from "../lockup/allow-to-hook/allowToHook.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; @@ -16,6 +17,7 @@ import { GetRefundedAmount_Integration_Concrete_Test } from "../lockup/get-refun import { GetSender_Integration_Concrete_Test } from "../lockup/get-sender/getSender.t.sol"; import { GetStartTime_Integration_Concrete_Test } from "../lockup/get-start-time/getStartTime.t.sol"; import { GetWithdrawnAmount_Integration_Concrete_Test } from "../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; +import { IsAllowedToHook_Integration_Concrete_Test } from "../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; import { IsCancelable_Integration_Concrete_Test } from "../lockup/is-cancelable/isCancelable.t.sol"; import { IsCold_Integration_Concrete_Test } from "../lockup/is-cold/isCold.t.sol"; import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDepleted.t.sol"; @@ -47,7 +49,7 @@ abstract contract LockupDynamic_Integration_Concrete_Test is Integration_Test, L Integration_Test.setUp(); LockupDynamic_Integration_Shared_Test.setUp(); - // Cast the LockupDynamic contract as {ISablierV2Lockup}. + // Cast the {LockupDynamic} contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupDynamic); } } @@ -56,6 +58,20 @@ abstract contract LockupDynamic_Integration_Concrete_Test is Integration_Test, L SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ +contract AllowToHook_LockupDynamic_Integration_Concrete_Test is + LockupDynamic_Integration_Concrete_Test, + AllowToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupDynamic_Integration_Concrete_Test, AllowToHook_Integration_Concrete_Test) + { + LockupDynamic_Integration_Concrete_Test.setUp(); + AllowToHook_Integration_Concrete_Test.setUp(); + } +} + contract Burn_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, Burn_Integration_Concrete_Test @@ -206,6 +222,20 @@ contract GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test is } } +contract IsAllowedToHook_LockupDynamic_Integration_Concrete_Test is + LockupDynamic_Integration_Concrete_Test, + IsAllowedToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupDynamic_Integration_Concrete_Test, IsAllowedToHook_Integration_Concrete_Test) + { + LockupDynamic_Integration_Concrete_Test.setUp(); + IsAllowedToHook_Integration_Concrete_Test.setUp(); + } +} + contract IsCancelable_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test, IsCancelable_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/integration/concrete/lockup-linear/LockupLinear.t.sol index e61e14aa2..5f6a3b246 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -5,6 +5,7 @@ import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; +import { AllowToHook_Integration_Concrete_Test } from "../lockup/allow-to-hook/allowToHook.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; @@ -16,6 +17,7 @@ import { GetRecipient_Integration_Concrete_Test } from "../lockup/get-recipient/ import { GetSender_Integration_Concrete_Test } from "../lockup/get-sender/getSender.t.sol"; import { GetStartTime_Integration_Concrete_Test } from "../lockup/get-start-time/getStartTime.t.sol"; import { GetWithdrawnAmount_Integration_Concrete_Test } from "../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; +import { IsAllowedToHook_Integration_Concrete_Test } from "../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; import { IsCancelable_Integration_Concrete_Test } from "../lockup/is-cancelable/isCancelable.t.sol"; import { IsCold_Integration_Concrete_Test } from "../lockup/is-cold/isCold.t.sol"; import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDepleted.t.sol"; @@ -47,7 +49,7 @@ abstract contract LockupLinear_Integration_Concrete_Test is Integration_Test, Lo Integration_Test.setUp(); LockupLinear_Integration_Shared_Test.setUp(); - // Cast the LockupLinear contract as {ISablierV2Lockup}. + // Cast the {LockupLinear} contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupLinear); } } @@ -56,6 +58,20 @@ abstract contract LockupLinear_Integration_Concrete_Test is Integration_Test, Lo SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ +contract AllowToHook_LockupLinear_Integration_Concrete_Test is + LockupLinear_Integration_Concrete_Test, + AllowToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupLinear_Integration_Concrete_Test, AllowToHook_Integration_Concrete_Test) + { + LockupLinear_Integration_Concrete_Test.setUp(); + AllowToHook_Integration_Concrete_Test.setUp(); + } +} + contract Burn_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, Burn_Integration_Concrete_Test @@ -206,6 +222,20 @@ contract GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test is } } +contract IsAllowedToHook_LockupLinear_Integration_Concrete_Test is + LockupLinear_Integration_Concrete_Test, + IsAllowedToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupLinear_Integration_Concrete_Test, IsAllowedToHook_Integration_Concrete_Test) + { + LockupLinear_Integration_Concrete_Test.setUp(); + IsAllowedToHook_Integration_Concrete_Test.setUp(); + } +} + contract IsCancelable_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test, IsCancelable_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol index 8e8e547a7..b19b02ffc 100644 --- a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -5,6 +5,7 @@ import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; +import { AllowToHook_Integration_Concrete_Test } from "../lockup/allow-to-hook/allowToHook.t.sol"; import { Burn_Integration_Concrete_Test } from "../lockup/burn/burn.t.sol"; import { Cancel_Integration_Concrete_Test } from "../lockup/cancel/cancel.t.sol"; import { CancelMultiple_Integration_Concrete_Test } from "../lockup/cancel-multiple/cancelMultiple.t.sol"; @@ -16,6 +17,7 @@ import { GetRefundedAmount_Integration_Concrete_Test } from "../lockup/get-refun import { GetSender_Integration_Concrete_Test } from "../lockup/get-sender/getSender.t.sol"; import { GetStartTime_Integration_Concrete_Test } from "../lockup/get-start-time/getStartTime.t.sol"; import { GetWithdrawnAmount_Integration_Concrete_Test } from "../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; +import { IsAllowedToHook_Integration_Concrete_Test } from "../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; import { IsCancelable_Integration_Concrete_Test } from "../lockup/is-cancelable/isCancelable.t.sol"; import { IsCold_Integration_Concrete_Test } from "../lockup/is-cold/isCold.t.sol"; import { IsDepleted_Integration_Concrete_Test } from "../lockup/is-depleted/isDepleted.t.sol"; @@ -50,7 +52,7 @@ abstract contract LockupTranched_Integration_Concrete_Test is Integration_Test.setUp(); LockupTranched_Integration_Shared_Test.setUp(); - // Cast the LockupTranched contract as {ISablierV2Lockup}. + // Cast the {LockupTranched} contract as {ISablierV2Lockup}. lockup = ISablierV2Lockup(lockupTranched); } } @@ -59,6 +61,20 @@ abstract contract LockupTranched_Integration_Concrete_Test is SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ +contract AllowToHook_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + AllowToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, AllowToHook_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + AllowToHook_Integration_Concrete_Test.setUp(); + } +} + contract Burn_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, Burn_Integration_Concrete_Test @@ -213,6 +229,20 @@ contract GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test is } } +contract IsAllowedToHook_LockupTranched_Integration_Concrete_Test is + LockupTranched_Integration_Concrete_Test, + IsAllowedToHook_Integration_Concrete_Test +{ + function setUp() + public + virtual + override(LockupTranched_Integration_Concrete_Test, IsAllowedToHook_Integration_Concrete_Test) + { + LockupTranched_Integration_Concrete_Test.setUp(); + IsAllowedToHook_Integration_Concrete_Test.setUp(); + } +} + contract IsCancelable_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test, IsCancelable_Integration_Concrete_Test diff --git a/test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol b/test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol new file mode 100644 index 000000000..c30daca79 --- /dev/null +++ b/test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/libraries/Errors.sol"; + +import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; +import { Integration_Test } from "../../../Integration.t.sol"; + +abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { + uint256 internal defaultStreamId; + + function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { + defaultStreamId = createDefaultStream(); + } + + function test_RevertWhen_CallerNotAdmin() external { + // Make Eve the caller in this test. + resetPrank({ msgSender: users.eve }); + + // Run the test. + vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); + lockup.allowToHook(users.eve); + } + + modifier whenCallerAdmin() { + // Make the Admin the caller in the rest of this test suite. + resetPrank({ msgSender: users.admin }); + _; + } + + function test_RevertWhen_ProvidedAddressNoCode() external whenCallerAdmin { + address eoa = vm.addr({ privateKey: 1 }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_AllowToHookZeroCodeSize.selector, eoa)); + lockup.allowToHook(eoa); + } + + modifier whenProvidedAddressHasCode() { + _; + } + + function test_RevertWhen_ProvidedAddressUnsupportedInterface() + external + whenCallerAdmin + whenProvidedAddressHasCode + { + // Incorrect interface ID. + address recipient = address(recipientInterfaceIDIncorrect); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2Lockup_AllowToHookUnsupportedInterface.selector, recipient) + ); + lockup.allowToHook(recipient); + + // Missing interface ID. + recipient = address(recipientInterfaceIDMissing); + vm.expectRevert(bytes("")); + lockup.allowToHook(recipient); + } + + modifier whenProvidedAddressSupportsInterface() { + _; + } + + function test_AllowToHook() + external + whenCallerAdmin + whenProvidedAddressHasCode + whenProvidedAddressSupportsInterface + { + // Expect the relevant event to be emitted. + vm.expectEmit({ emitter: address(lockup) }); + emit AllowToHook(users.admin, address(recipientGood)); + + // Allow the provided address to hook. + lockup.allowToHook(address(recipientGood)); + + // Assert that the provided address has been put on the allowlist. + bool isAllowedToHook = lockup.isAllowedToHook(address(recipientGood)); + assertTrue(isAllowedToHook, "address not put on the allowlist"); + } +} diff --git a/test/integration/concrete/lockup/allow-to-hook/allowToHook.tree b/test/integration/concrete/lockup/allow-to-hook/allowToHook.tree new file mode 100644 index 000000000..e8541e138 --- /dev/null +++ b/test/integration/concrete/lockup/allow-to-hook/allowToHook.tree @@ -0,0 +1,12 @@ +allowToHook.tree +├── when the caller is not the admin +│ └── it should revert +└── when the caller is the admin + ├── when the provided address doesn't have any code + │ └── it should revert + └── when the provided address has code + ├── when the provided address does not support the recipient interface + │ └── it should revert + └── when the provided address supports the recipient interface + ├── it should put the address on the allowlist + └── it should emit a {AllowToHook} event diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/integration/concrete/lockup/cancel/cancel.t.sol index 6566400ff..cca169686 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/integration/concrete/lockup/cancel/cancel.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup } from "src/types/DataTypes.sol"; @@ -110,7 +110,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I assertFalse(isCancelable, "isCancelable"); } - function test_Cancel_RecipientNotContract() + function test_Cancel_RecipientNotAllowedToHook() external whenNotDelegateCalled givenNotNull @@ -119,13 +119,30 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I givenStreamCancelable givenStatusStreaming { - lockup.cancel(defaultStreamId); - Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); + // Create the stream with a recipient contract that implements {ISablierLockupRecipient}. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); + + // Expect Sablier to NOT run the recipient hook. + uint128 senderAmount = lockup.refundableAmountOf(streamId); + uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); + vm.expectCall({ + callee: address(recipientGood), + data: abi.encodeCall( + ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) + ), + count: 0 + }); + + // Cancel the stream. + lockup.cancel(streamId); + + // Assert that the stream has been canceled. + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.CANCELED; assertEq(actualStatus, expectedStatus); } - function test_Cancel_RecipientDoesNotImplementHook() + function test_Cancel_RecipientReverting() external whenNotDelegateCalled givenNotNull @@ -133,31 +150,24 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerAuthorized givenStreamCancelable givenStatusStreaming - givenRecipientContract + givenRecipientAllowedToHook { - // Create the stream with a no-op contract as the recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(noop)); + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientReverting)); + resetPrank({ msgSender: users.sender }); - // Expect a call to the hook. - uint128 senderAmount = lockup.refundableAmountOf(streamId); - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); - vm.expectCall( - address(noop), - abi.encodeCall( - ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) - ) - ); + // Create the stream with a reverting contract as the stream's recipient. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientReverting)); + + // Expect a revert. + vm.expectRevert("You shall not pass"); // Cancel the stream. lockup.cancel(streamId); - - // Assert that the stream has been canceled. - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.CANCELED; - assertEq(actualStatus, expectedStatus); } - function test_Cancel_RecipientReverts() + function test_Cancel_RecipientReturnsInvalidSelector() external whenNotDelegateCalled givenNotNull @@ -165,32 +175,29 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerAuthorized givenStreamCancelable givenStatusStreaming - givenRecipientContract - givenRecipientImplementsHook + givenRecipientAllowedToHook + whenRecipientNotReverting { - // Create the stream with a reverting contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(revertingRecipient)); + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientInvalidSelector)); + resetPrank({ msgSender: users.sender }); - // Expect a call to the hook. - uint128 senderAmount = lockup.refundableAmountOf(streamId); - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); - vm.expectCall( - address(revertingRecipient), - abi.encodeCall( - ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + // Create the stream with a recipient contract that returns invalid selector bytes on the hook call. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientInvalidSelector)); + + // Expect a revert. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2Lockup_InvalidHookSelector.selector, address(recipientInvalidSelector) ) ); // Cancel the stream. lockup.cancel(streamId); - - // Assert that the stream has been canceled. - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.CANCELED; - assertEq(actualStatus, expectedStatus); } - function test_Cancel_RecipientReentrancy() + function test_Cancel_RecipientReentrant() external whenNotDelegateCalled givenNotNull @@ -198,30 +205,45 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerAuthorized givenStreamCancelable givenStatusStreaming - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert + givenRecipientAllowedToHook + whenRecipientNotReverting + whenRecipientReturnsSelector { + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientReentrant)); + resetPrank({ msgSender: users.sender }); + // Create the stream with a reentrant contract as the recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(reentrantRecipient)); + uint256 streamId = createDefaultStreamWithRecipient(address(recipientReentrant)); - // Expect a call to the hook. + // Expect Sablier to run the recipient hook. uint128 senderAmount = lockup.refundableAmountOf(streamId); uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); vm.expectCall( - address(reentrantRecipient), + address(recipientReentrant), abi.encodeCall( - ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) ) ); + // Expect a reentrant call to the Lockup contract. + vm.expectCall( + address(lockup), + abi.encodeCall(ISablierV2Lockup.withdraw, (streamId, address(recipientReentrant), recipientAmount)) + ); + // Cancel the stream. lockup.cancel(streamId); - // Assert that the stream has been canceled. + // Assert that the stream has been depleted. The reentrant recipient withdrew all the funds. Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.CANCELED; + Lockup.Status expectedStatus = Lockup.Status.DEPLETED; assertEq(actualStatus, expectedStatus); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + assertEq(actualWithdrawnAmount, recipientAmount, "withdrawnAmount"); } function test_Cancel() @@ -232,30 +254,35 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerAuthorized givenStreamCancelable givenStatusStreaming - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - whenNoRecipientReentrancy + givenRecipientAllowedToHook + whenRecipientNotReverting + whenRecipientReturnsSelector + whenRecipientNotReentrant { + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + resetPrank({ msgSender: users.sender }); + // Create the stream. - uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); // Expect the assets to be refunded to the Sender. uint128 senderAmount = lockup.refundableAmountOf(streamId); expectCallToTransfer({ to: users.sender, value: senderAmount }); - // Expect a call to the hook. + // Expect Sablier to run the recipient hook. uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); vm.expectCall( - address(goodRecipient), + address(recipientGood), abi.encodeCall( - ISablierV2Recipient.onLockupStreamCanceled, (streamId, users.sender, senderAmount, recipientAmount) + ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) ) ); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit CancelLockupStream(streamId, users.sender, address(goodRecipient), dai, senderAmount, recipientAmount); + emit CancelLockupStream(streamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); @@ -278,7 +305,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I // Assert that the NFT has not been burned. address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = address(goodRecipient); + address expectedNFTOwner = address(recipientGood); assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/integration/concrete/lockup/cancel/cancel.tree b/test/integration/concrete/lockup/cancel/cancel.tree index 52c1ae929..dab8a48a2 100644 --- a/test/integration/concrete/lockup/cancel/cancel.tree +++ b/test/integration/concrete/lockup/cancel/cancel.tree @@ -27,33 +27,29 @@ cancel.t.sol │ ├── it should mark the stream as depleted │ └── it should make the stream not cancelable └── given the stream's status is "STREAMING" - ├── given the recipient is not a contract + ├── given the recipient is not allowed to hook │ ├── it should cancel the stream - │ └── it should mark the stream as canceled - └── given the recipient is a contract - ├── given the recipient does not implement the hook - │ ├── it should cancel the stream - │ ├── it should mark the stream as canceled - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── given the recipient implements the hook - ├── when the recipient reverts + │ ├── it should mark the stream as canceled + │ └── it should not make Sablier run the recipient hook + └── given the recipient is allowed to hook + ├── when the recipient reverts + │ └── it should revert the entire transaction + └── when the recipient does not revert + ├── when the recipient hook does not return a valid selector + │ └── it should revert + └── when the recipient hook returns a valid selector + ├── when there is reentrancy │ ├── it should cancel the stream │ ├── it should mark the stream as canceled - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when the recipient does not revert - ├── when there is reentrancy - │ ├── it should cancel the stream - │ ├── it should mark the stream as canceled - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when there is no reentrancy - ├── it should cancel the stream - ├── it should mark the stream as canceled - ├── it should make the stream not cancelable - ├── it should update the refunded amount - ├── it should refund the sender - ├── it should call the recipient hook - ├── it should emit a {MetadataUpdate} event - └── it should emit a {CancelLockupStream} event + │ ├── it should make Sablier run the recipient hook + │ ├── it should perform a reentrancy call to the Lockup contract + │ └── it should make the withdrawal via the reentrancy + └── when there is no reentrancy + ├── it should cancel the stream + ├── it should mark the stream as canceled + ├── it should make the stream not cancelable + ├── it should update the refunded amount + ├── it should refund the sender + ├── it should make Sablier run the recipient hook + ├── it should emit a {MetadataUpdate} event + └── it should emit a {CancelLockupStream} event diff --git a/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol b/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol new file mode 100644 index 000000000..ed92d5fcb --- /dev/null +++ b/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; +import { Integration_Test } from "../../../Integration.t.sol"; + +abstract contract IsAllowedToHook_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { + uint256 internal defaultStreamId; + + function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { + defaultStreamId = createDefaultStream(); + } + + function test_IsAllowedToHook_GivenProvidedAddressIsNotAllowedToHook() external view { + bool result = lockup.isAllowedToHook(address(recipientGood)); + assertFalse(result, "isAllowedToHook"); + } + + modifier givenProvidedAddressIsAllowedToHook() { + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + _; + } + + function test_IsAllowedToHook() external givenProvidedAddressIsAllowedToHook { + bool result = lockup.isAllowedToHook(address(recipientGood)); + assertTrue(result, "isAllowedToHook"); + } +} diff --git a/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree b/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree new file mode 100644 index 000000000..9196064ef --- /dev/null +++ b/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree @@ -0,0 +1,5 @@ +isAllowedToHook.tree +├── given the provided address is not allowed to hook +│ └── it should return false +└── given the provided address is allowed to hook + └── it should return true diff --git a/test/integration/concrete/lockup/renounce/renounce.t.sol b/test/integration/concrete/lockup/renounce/renounce.t.sol index 00a2c5da3..b6b91fed1 100644 --- a/test/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/integration/concrete/lockup/renounce/renounce.t.sol @@ -2,7 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; @@ -98,123 +97,9 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup _; } - function test_Renounce_RecipientNotContract() - external - whenNotDelegateCalled - givenStreamWarm - whenCallerSender - givenStreamCancelable - { - lockup.renounce(defaultStreamId); - bool isCancelable = lockup.isCancelable(defaultStreamId); - assertFalse(isCancelable, "isCancelable"); - } - - modifier givenRecipientContract() { - _; - } - - function test_Renounce_RecipientDoesNotImplementHook() - external - whenNotDelegateCalled - givenStreamWarm - whenCallerSender - givenStreamCancelable - givenRecipientContract - { - // Create the stream with a no-op contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(noop)); - - // Expect a call to the hook. - vm.expectCall(address(noop), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId))); - - // Renounce the stream. - lockup.renounce(streamId); - - // Assert that the stream is not cancelable anymore. - bool isCancelable = lockup.isCancelable(streamId); - assertFalse(isCancelable, "isCancelable"); - } - - modifier givenRecipientImplementsHook() { - _; - } - - function test_Renounce_RecipientReverts() - external - whenNotDelegateCalled - givenStreamWarm - whenCallerSender - givenStreamCancelable - givenRecipientContract - givenRecipientImplementsHook - { - // Create the stream with a reverting contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(revertingRecipient)); - - // Expect a call to the hook. - vm.expectCall( - address(revertingRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId)) - ); - - // Renounce the stream. - lockup.renounce(streamId); - - // Assert that the stream is not cancelable anymore. - bool isCancelable = lockup.isCancelable(streamId); - assertFalse(isCancelable, "isCancelable"); - } - - modifier whenRecipientDoesNotRevert() { - _; - } - - function test_Renounce_RecipientReentrancy() - external - whenNotDelegateCalled - givenStreamWarm - whenCallerSender - givenStreamCancelable - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - { - // Create the stream with a reentrant contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(reentrantRecipient)); - - // Expect a call to the hook. - vm.expectCall( - address(reentrantRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId)) - ); - - // Renounce the stream. - lockup.renounce(streamId); - - // Assert that the stream is not cancelable anymore. - bool isCancelable = lockup.isCancelable(streamId); - assertFalse(isCancelable, "isCancelable"); - } - - modifier whenNoRecipientReentrancy() { - _; - } - - function test_Renounce() - external - whenNotDelegateCalled - givenStreamWarm - whenCallerSender - givenStreamCancelable - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - whenNoRecipientReentrancy - { + function test_Renounce() external whenNotDelegateCalled givenStreamWarm whenCallerSender givenStreamCancelable { // Create the stream with a contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); - - // Expect a call to the hook. - vm.expectCall(address(goodRecipient), abi.encodeCall(ISablierV2Recipient.onLockupStreamRenounced, (streamId))); + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); diff --git a/test/integration/concrete/lockup/renounce/renounce.tree b/test/integration/concrete/lockup/renounce/renounce.tree index 1a80ac4d5..f354e61c6 100644 --- a/test/integration/concrete/lockup/renounce/renounce.tree +++ b/test/integration/concrete/lockup/renounce/renounce.tree @@ -16,25 +16,9 @@ renounce.t.sol ├── when the caller is not the sender │ └── it should revert └── when the caller is the sender - ├── given the recipient is not a contract - │ └── it should renounce the stream - └── given the recipient is a contract - ├── given the recipient does not implement the hook - │ ├── it should renounce the stream - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── given the recipient implements the hook - ├── when the recipient reverts - │ ├── it should renounce the stream - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when the recipient does not revert - ├── when there is reentrancy - │ ├── it should renounce the stream - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when there is no reentrancy - ├── it should renounce the stream - ├── it should call the recipient hook - ├── it should emit a {RenounceLockupStream} event - └── it should emit a {MetadataUpdate} event + ├── given the stream is not cancelable + │ └── it should revert + └── given the stream is cancelable + ├── it should renounce the stream + ├── it should emit a {RenounceLockupStream} event + └── it should emit a {MetadataUpdate} event diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol index 27c0157c6..a89bc2c07 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; -import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; +import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; import { Integration_Test } from "../../../Integration.t.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; @@ -13,253 +12,135 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test, W function setUp() public virtual override(Integration_Test, Withdraw_Integration_Shared_Test) { Withdraw_Integration_Shared_Test.setUp(); withdrawAmount = defaults.WITHDRAW_AMOUNT(); - } - - modifier givenDifferentSenderAndRecipient() { - _; - } - - function test_WithdrawHooks_CallerUnknown() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - address unknownCaller = address(0xCAFE); - - // Create the stream with both the sender and the recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Make `unknownCaller` the caller in this test. - resetPrank({ msgSender: unknownCaller }); - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - - // Expect a call to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + // Allow the good recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + resetPrank({ msgSender: users.sender }); } - function test_WithdrawHooks_CallerApprovedOperator() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with both the sender and the recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Approve the operator to handle the stream. - resetPrank({ msgSender: address(goodRecipient) }); - lockup.approve({ to: users.operator, tokenId: streamId }); - - // Make the operator the caller in this test. - resetPrank({ msgSender: users.operator }); + function test_WithdrawHooks_GivenSameSenderAndRecipient() external { + // Create a stream with identical sender and recipient. + uint256 streamId = createDefaultStreamWithIdenticalUsers(users.sender); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Expect a call to the recipient hook. + // Expect Sablier to NOT run the user hook. vm.expectCall({ - callee: address(goodRecipient), + callee: users.sender, data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, users.operator, address(goodRecipient), withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, (streamId, users.sender, users.sender, withdrawAmount) ), - count: 1 - }); - - // Expect a call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodRecipient), withdrawAmount) - ), - count: 1 + count: 0 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: users.sender, amount: withdrawAmount }); } - function test_WithdrawHooks_CallerSender() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with both the sender and the recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); - - // Make the sender the caller in this test. - resetPrank({ msgSender: address(goodSender) }); - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - - // Expect 1 call to the recipient hook. - vm.expectCall({ - callee: address(goodRecipient), - data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), - count: 1 - }); - - // Expect no calls to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodRecipient), withdrawAmount) - ), - count: 0 - }); - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + modifier givenDifferentSenderAndRecipient() { + _; } - function test_WithdrawHooks_CallerRecipient() - external - givenSenderContract - givenRecipientContract - givenDifferentSenderAndRecipient - { - // Create the stream with both the sender and the recipient as contracts. - uint256 streamId = createDefaultStreamWithUsers(address(goodRecipient), address(goodSender)); + function test_WithdrawHooks_CallerUnknown() external givenDifferentSenderAndRecipient { + // Create the test stream. + uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Make the recipient the caller in this test. - resetPrank({ msgSender: address(goodRecipient) }); + // Make the unknown address the caller in this test. + address unknownCaller = address(0xCAFE); + resetPrank({ msgSender: unknownCaller }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Expect no calls to the recipient hook. + // Expect Sablier to run the recipient hook. vm.expectCall({ - callee: address(goodRecipient), + callee: address(recipientGood), data: abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) - ), - count: 0 - }); - - // Expect 1 call to the sender hook. - vm.expectCall({ - callee: address(goodSender), - data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodRecipient), address(goodRecipient), withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, unknownCaller, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); } - modifier givenSameSenderAndRecipient() { - _; - } + function test_WithdrawHooks_CallerApprovedOperator() external givenDifferentSenderAndRecipient { + // Create the test stream. + uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - function test_WithdrawHooks_SenderHook_CallerUnknown() external givenSenderContract givenSameSenderAndRecipient { - address unknownCaller = address(0xCAFE); - - // Create the stream with the recipient as the sender. - uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); + // Approve the operator to handle the stream. + resetPrank({ msgSender: address(recipientGood) }); + lockup.approve({ to: users.operator, tokenId: streamId }); - // Make unknownCaller the caller in this test. - resetPrank({ msgSender: unknownCaller }); + // Make the operator the caller in this test. + resetPrank({ msgSender: users.operator }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Expect a call to the sender hook. + // Expect Sablier to run the recipient hook. vm.expectCall({ - callee: address(goodSender), + callee: address(recipientGood), data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, unknownCaller, address(goodSender), withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, users.operator, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); } - function test_WithdrawHooks_SenderHook_CallerApprovedOperator() - external - givenSenderContract - givenSameSenderAndRecipient - { - // Create the stream with recipient which is same as the sender contract. - uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); - - // Approve the operator to handle the stream. - resetPrank({ msgSender: address(goodSender) }); - lockup.approve({ to: users.operator, tokenId: streamId }); + function test_WithdrawHooks_CallerSender() external givenDifferentSenderAndRecipient { + // Create the test stream. + uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Make the operator the caller in this test. - resetPrank({ msgSender: users.operator }); + // Make the Sender the caller in this test. + resetPrank({ msgSender: users.sender }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Expect a call to the sender hook. + // Expect Sablier to run the recipient hook. vm.expectCall({ - callee: address(goodSender), + callee: address(recipientGood), data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.operator, address(goodSender), withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, users.sender, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); } - function test_WithdrawHooks_SenderHook_CallerSender() external givenSenderContract givenSameSenderAndRecipient { - // Create the stream with the sender as the recipient. - uint256 streamId = createDefaultStreamWithIdenticalUsers(address(goodSender)); + function test_WithdrawHooks_CallerRecipient() external givenDifferentSenderAndRecipient { + // Create the test stream. + uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Approve the operator to handle the stream. - resetPrank({ msgSender: address(goodSender) }); + // Make the recipient contract the caller in this test. + resetPrank({ msgSender: address(recipientGood) }); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Expect no calls to the sender hook. + // Expect Sablier to NOT run the recipient hook. vm.expectCall({ - callee: address(goodSender), + callee: address(recipientGood), data: abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, - (streamId, address(goodSender), address(goodSender), withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, address(recipientGood), address(recipientGood), withdrawAmount) ), count: 0 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(goodSender), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); } } diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree index f0500c61a..dd552a01b 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree +++ b/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree @@ -1,21 +1,12 @@ withdrawHooks.t.sol -├── given the recipient is different than the sender -│ ├── when the caller is unknown -│ │ ├── it should make one hook call to the sender -│ │ └── it should make one hook call to the recipient -│ ├── when the caller is an approved third party -│ │ ├── it should make one hook call to the sender -│ │ └── it should make one hook call to the recipient -│ ├── when the caller is the sender -│ │ ├── it should not make any hook call to the sender -│ │ └── it should make one hook call to the recipient -│ └── when the caller is the recipient -│ ├── it should make one hook call to the sender -│ └── it should not make any hook call to the recipient -└── given the recipient is the same as the sender - ├── when the caller is unknown - │ └── it should make one hook call to the sender - ├── when the caller is an approved third party - │ └── it should make one hook call to the sender - └── when the caller is the sender - └── it should not make any hook call to the sender +├── given the recipient is the same as the sender +│ └── it should not make Sablier run the user hook +└── given the recipient is different than the sender + ├── when the caller is unknown + │ └── it should make Sablier run the recipient hook + ├── when the caller is an approved third party + │ └── it should make Sablier run the recipient hook + ├── when the caller is the sender + │ └── it should make Sablier run the recipient hook + └── when the caller is the recipient + └── it should not make Sablier run the recipient hook diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/integration/concrete/lockup/withdraw/withdraw.t.sol index e7a72167e..66815be10 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2Recipient } from "src/interfaces/hooks/ISablierV2Recipient.sol"; -import { ISablierV2Sender } from "src/interfaces/hooks/ISablierV2Sender.sol"; import { Errors } from "src/libraries/Errors.sol"; import { Lockup } from "src/types/DataTypes.sol"; @@ -183,7 +182,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - function test_Withdraw_SenderNotContract() + function test_Withdraw_CallerRecipient1() external whenNotDelegateCalled givenNotNull @@ -192,127 +191,32 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawAmountNotZero whenNoOverdraw whenWithdrawalAddressNotRecipient - whenCallerRecipient { - test_Withdraw_CallerRecipient(defaultStreamId, users.sender); - } - - function test_Withdraw_SenderDoesNotImplementHook() - external - whenNotDelegateCalled - givenNotNull - givenStreamNotDepleted - whenToNonZeroAddress - whenWithdrawAmountNotZero - whenNoOverdraw - whenWithdrawalAddressNotRecipient - whenCallerRecipient - givenSenderContract - { - // Create the stream with a noop contract as the stream's sender. - uint256 streamId = createDefaultStreamWithSender(address(noop)); - - test_Withdraw_CallerRecipient(streamId, address(noop)); - } - - modifier givenSenderImplementsHook() { - _; - } - - function test_Withdraw_ReentrancySender() - external - whenNotDelegateCalled - givenNotNull - givenStreamNotDepleted - whenToNonZeroAddress - whenWithdrawAmountNotZero - whenNoOverdraw - whenWithdrawalAddressNotRecipient - whenCallerRecipient - givenSenderContract - givenSenderImplementsHook - { - // Create the stream with a reentrant contract as the stream's sender. - uint256 streamId = createDefaultStreamWithSender(address(reentrantSender)); - // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - // Halve the withdraw amount so that the recipient can re-entry and make another withdrawal. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT() / 2; + // Set the withdraw amount to the default amount. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - // Expect a call to the hook. - vm.expectCall( - address(reentrantSender), - abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) - ) - ); + // Expect the assets to be transferred to Alice. + expectCallToTransfer({ to: users.alice, value: withdrawAmount }); - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(lockup) }); + emit WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.alice, asset: dai, amount: withdrawAmount }); + vm.expectEmit({ emitter: address(lockup) }); + emit MetadataUpdate({ _tokenId: defaultStreamId }); - // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.STREAMING; - assertEq(actualStatus, expectedStatus); + // Make the withdrawal. + lockup.withdraw({ streamId: defaultStreamId, to: users.alice, amount: withdrawAmount }); // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - modifier whenNoSenderReentrancy() { - _; - } - - function test_Withdraw_RevertingSender() - external - whenNotDelegateCalled - givenNotNull - givenStreamNotDepleted - whenToNonZeroAddress - whenWithdrawAmountNotZero - whenNoOverdraw - whenWithdrawalAddressNotRecipient - whenCallerRecipient - givenSenderContract - givenSenderImplementsHook - whenNoSenderReentrancy - { - // Create the stream with a contract as the stream's sender. - uint256 streamId = createDefaultStreamWithSender(address(revertingSender)); - - test_Withdraw_CallerRecipient(streamId, address(revertingSender)); - } - - modifier whenSenderDoesNotRevert() { - _; - } - - function test_Withdraw_GoodSender() - external - whenNotDelegateCalled - givenNotNull - givenStreamNotDepleted - whenToNonZeroAddress - whenWithdrawAmountNotZero - whenNoOverdraw - whenWithdrawalAddressNotRecipient - whenCallerRecipient - givenSenderContract - givenSenderImplementsHook - whenNoSenderReentrancy - whenSenderDoesNotRevert - { - // Create the stream with a contract as the stream's sender. - uint256 streamId = createDefaultStreamWithSender(address(goodSender)); - - test_Withdraw_CallerRecipient(streamId, address(goodSender)); - } - - function test_Withdraw_CallerUnknownAddress() + function test_Withdraw_CallerUnknown() external whenNotDelegateCalled givenNotNull @@ -337,7 +241,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - function test_Withdraw_CallerRecipient() + function test_Withdraw_CallerRecipient2() external whenNotDelegateCalled givenNotNull @@ -359,11 +263,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - modifier whenCallerSender() { - resetPrank({ msgSender: users.sender }); - _; - } - function test_Withdraw_EndTimeNotInTheFuture() external whenNotDelegateCalled @@ -396,12 +295,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } - modifier givenEndTimeInTheFuture() { - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - _; - } - function test_Withdraw_StreamHasBeenCanceled() external whenNotDelegateCalled @@ -439,7 +332,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } - function test_Withdraw_RecipientNotContract() + function test_Withdraw_RecipientNotAllowedToHook() external whenNotDelegateCalled givenNotNull @@ -452,10 +345,30 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr givenEndTimeInTheFuture whenStreamHasNotBeenCanceled { - test_Withdraw_CallerSender(defaultStreamId, users.recipient); + // Create the stream with a recipient contract that implements {ISablierLockupRecipient}. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); + + // Expect Sablier to NOT run the recipient hook. + uint128 withdrawAmount = lockup.withdrawableAmountOf(streamId); + vm.expectCall({ + callee: address(recipientGood), + data: abi.encodeCall( + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, users.sender, address(recipientGood), withdrawAmount) + ), + count: 0 + }); + + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + + // Assert that the withdrawn amount has been updated. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 expectedWithdrawnAmount = withdrawAmount; + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - function test_Withdraw_RecipientDoesNotImplementHook() + function test_Withdraw_RecipientReverting() external whenNotDelegateCalled givenNotNull @@ -467,19 +380,25 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled - givenRecipientContract + givenRecipientAllowedToHook { - // Create the stream with a noop contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(noop)); + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientReverting)); + resetPrank({ msgSender: users.sender }); - test_Withdraw_CallerSender(streamId, address(noop)); - } + // Create the stream with a reverting contract as the stream's recipient. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientReverting)); + + // Expect a revert. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + vm.expectRevert("You shall not pass"); - modifier givenRecipientImplementsHook() { - _; + // Make the withdrawal. + lockup.withdraw({ streamId: streamId, to: address(recipientReverting), amount: withdrawAmount }); } - function test_Withdraw_RecipientReverts() + function test_Cancel_RecipientReturnsInvalidSelector() external whenNotDelegateCalled givenNotNull @@ -491,20 +410,30 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled - givenRecipientContract - givenRecipientImplementsHook + givenRecipientAllowedToHook + whenRecipientNotReverting { - // Create the stream with a reverting contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(revertingRecipient)); + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientInvalidSelector)); + resetPrank({ msgSender: users.sender }); - test_Withdraw_CallerSender(streamId, address(revertingRecipient)); - } + // Create the stream with a recipient contract that returns invalid selector bytes on the hook call. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientInvalidSelector)); - modifier whenRecipientDoesNotRevert() { - _; + // Expect a revert. + uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2Lockup_InvalidHookSelector.selector, address(recipientInvalidSelector) + ) + ); + + // Cancel the stream. + lockup.withdraw({ streamId: streamId, to: address(recipientInvalidSelector), amount: withdrawAmount }); } - function test_Withdraw_RecipientReentrancy() + function test_Withdraw_RecipientReentrant() external whenNotDelegateCalled givenNotNull @@ -516,27 +445,23 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert + givenRecipientAllowedToHook + whenRecipientNotReverting + whenRecipientReturnsSelector { + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientReentrant)); + resetPrank({ msgSender: users.sender }); + // Create the stream with a reentrant contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(reentrantRecipient)); + uint256 streamId = createDefaultStreamWithRecipient(address(recipientReentrant)); // Halve the withdraw amount so that the recipient can re-entry and make another withdrawal. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT() / 2; - // Expect a call to the hook. - vm.expectCall( - address(reentrantRecipient), - abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, users.sender, address(reentrantRecipient), withdrawAmount) - ) - ); - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(reentrantRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientReentrant), amount: withdrawAmount }); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); @@ -549,10 +474,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } - modifier whenNoRecipientReentrancy() { - _; - } - function test_Withdraw() external whenNotDelegateCalled @@ -565,73 +486,47 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenCallerSender givenEndTimeInTheFuture whenStreamHasNotBeenCanceled - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - whenNoRecipientReentrancy + givenRecipientAllowedToHook + whenRecipientNotReverting + whenRecipientReturnsSelector + whenRecipientNotReentrant { - // Create the stream with a contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); - - test_Withdraw_CallerSender(streamId, address(goodRecipient)); - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL HELPERS - //////////////////////////////////////////////////////////////////////////*/ - - function test_Withdraw_CallerRecipient(uint256 streamId, address sender) internal { - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the default amount. - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - - // Expect a call to the hook if the sender is a contract. - if (sender.code.length > 0) { - vm.expectCall( - address(sender), - abi.encodeCall( - ISablierV2Sender.onLockupStreamWithdrawn, (streamId, users.recipient, users.alice, withdrawAmount) - ) - ); - } - - // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: users.alice, amount: withdrawAmount }); + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + resetPrank({ msgSender: users.sender }); - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); - uint128 expectedWithdrawnAmount = withdrawAmount; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); - } + // Create the stream with a contract as the stream's recipient. + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - function test_Withdraw_CallerSender(uint256 streamId, address recipient) internal { // Set the withdraw amount to the default amount. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); // Expect the assets to be transferred to the recipient contract. - expectCallToTransfer({ to: address(recipient), value: withdrawAmount }); + expectCallToTransfer({ to: address(recipientGood), value: withdrawAmount }); // Expect a call to the hook if the recipient is a contract. - if (recipient.code.length > 0) { - vm.expectCall( - address(recipient), - abi.encodeCall( - ISablierV2Recipient.onLockupStreamWithdrawn, - (streamId, users.sender, address(recipient), withdrawAmount) - ) - ); - } + vm.expectCall( + address(recipientGood), + abi.encodeCall( + ISablierLockupRecipient.onSablierLockupWithdraw, + (streamId, users.sender, address(recipientGood), withdrawAmount) + ) + ); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit WithdrawFromLockupStream({ streamId: streamId, to: address(recipient), asset: dai, amount: withdrawAmount }); + emit WithdrawFromLockupStream({ + streamId: streamId, + to: address(recipientGood), + asset: dai, + amount: withdrawAmount + }); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); diff --git a/test/integration/concrete/lockup/withdraw/withdraw.tree b/test/integration/concrete/lockup/withdraw/withdraw.tree index 8cf51bdf3..32a43c469 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.tree +++ b/test/integration/concrete/lockup/withdraw/withdraw.tree @@ -2,102 +2,75 @@ withdraw.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── given the ID references a null stream - │ └── it should revert - └── given the ID does not reference a null stream - ├── given the stream's status is "DEPLETED" - │ └── it should revert - └── given the stream's status is not "DEPLETED" - ├── when the provided address is zero - │ └── it should revert - └── when the provided address is not zero - ├── when the withdraw amount is zero - │ └── it should revert - └── when the withdraw amount is not zero - ├── when the withdraw amount overdraws - │ └── it should revert - └── when the withdraw amount does not overdraw - ├── when the withdrawal address is not the stream recipient - │ ├── when the caller is unknown - │ │ └── it should revert - │ ├── when the caller is the sender - │ │ └── it should revert - │ ├── when the caller is a former recipient - │ │ └── it should revert - │ ├── when the caller is an approved third party - │ │ ├── it should make the withdrawal - │ │ └── it should update the withdrawn amount - │ └── when the caller is the recipient - │ ├── given the sender is not a contract - │ │ ├── it should make the withdrawal - │ │ └── it should update the withdrawn amount - │ └── given the sender is a contract - │ ├── given the sender does not implement the hook - │ │ ├── it should make the withdrawal - │ │ ├── it should update the withdrawn amount - │ │ ├── it should call the sender hook - │ │ └── it should ignore the revert - │ └── given the sender implements the hook - │ ├── when the sender reverts - │ │ ├── it should make the withdrawal - │ │ ├── it should update the withdrawn amount - │ │ ├── it should call the sender hook - │ │ └── it should ignore the revert - │ └── when the sender does not revert - │ ├── when there is reentrancy - │ │ ├── it should make multiple withdrawals - │ │ ├── it should update the withdrawn amounts - │ │ └── it should call the sender hooks - │ └── when there is no reentrancy - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the sender hook - │ ├── it should emit a {MetadataUpdate} event - │ └── it should emit a {WithdrawFromLockupStream} event - └── when the withdrawal address is the stream recipient - ├── when the caller is unknown - │ ├── it should make the withdrawal - │ └── it should update the withdrawn amount - ├── when the caller is the recipient - │ ├── it should make the withdrawal - │ └── it should update the withdrawn amount - └── when the caller is the sender - ├── given the end time is not in the future - │ ├── it should make the withdrawal - │ ├── it should mark the stream as depleted - │ └── it should make the stream not cancelable - └── given the end time is in the future - ├── given the stream has been canceled - │ ├── it should make the withdrawal - │ ├── it should mark the stream as depleted - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ ├── it should emit a {MetadataUpdate} event - │ └── it should emit a {WithdrawFromLockupStream} event - └── given the stream has not been canceled - ├── given the recipient is not a contract - │ └── it should make the withdrawal - │ └── it should update the withdrawn amount - └── given the recipient is a contract - ├── given the recipient does not implement the hook - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── given the recipient implements the hook - ├── when the recipient reverts - │ ├── it should make the withdrawal - │ ├── it should update the withdrawn amount - │ ├── it should call the recipient hook - │ └── it should ignore the revert - └── when the recipient does not revert - ├── when there is reentrancy - │ ├── it should make multiple withdrawals - │ ├── it should update the withdrawn amounts - │ └── it should call the recipient hooks - └── when there is no reentrancy - ├── it should make the withdrawal - ├── it should update the withdrawn amount - ├── it should call the recipient hook - ├── it should emit a {MetadataUpdate} event - └── it should emit a {WithdrawFromLockupStream} event + ├── given the ID references a null stream + │ └── it should revert + └── given the ID does not reference a null stream + ├── given the stream's status is "DEPLETED" + │ └── it should revert + └── given the stream's status is not "DEPLETED" + ├── when the provided address is zero + │ └── it should revert + └── when the provided address is not zero + ├── when the withdraw amount is zero + │ └── it should revert + └── when the withdraw amount is not zero + ├── when the withdraw amount overdraws + │ └── it should revert + └── when the withdraw amount does not overdraw + ├── when the withdrawal address is not the stream recipient + │ ├── when the caller is unknown + │ │ └── it should revert + │ ├── when the caller is the sender + │ │ └── it should revert + │ ├── when the caller is a former recipient + │ │ └── it should revert + │ ├── when the caller is an approved third party + │ │ ├── it should make the withdrawal + │ │ └── it should update the withdrawn amount + │ └── when the caller is the recipient + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── when the withdrawal address is the stream recipient + ├── when the caller is unknown + │ ├── it should make the withdrawal + │ └── it should update the withdrawn amount + ├── when the caller is the recipient + │ ├── it should make the withdrawal + │ └── it should update the withdrawn amount + └── when the caller is the sender + ├── given the end time is not in the future + │ ├── it should make the withdrawal + │ ├── it should mark the stream as depleted + │ └── it should make the stream not cancelable + └── given the end time is in the future + ├── given the stream has been canceled + │ ├── it should make the withdrawal + │ ├── it should mark the stream as depleted + │ ├── it should update the withdrawn amount + │ ├── it should make Sablier run the recipient hook + │ ├── it should emit a {MetadataUpdate} event + │ └── it should emit a {WithdrawFromLockupStream} event + └── given the stream has not been canceled + ├── given the recipient is not allowed to hook + │ ├── it should make the withdrawal + │ ├── it should update the withdrawn amount + │ └── it should not make Sablier run the recipient hook + └── given the recipient is allowed to hook + ├── when the recipient reverts + │ └── it should revert the entire transaction + └── when the recipient does not revert + ├── when the recipient hook does not return a valid selector + │ └── it should revert + └── when the recipient hook returns a valid selector + ├── when there is reentrancy + │ ├── it should make multiple withdrawals + │ ├── it should update the withdrawn amounts + │ └── it should make Sablier run the recipient hook + └── when there is no reentrancy + ├── it should make the withdrawal + ├── it should update the withdrawn amount + ├── it should make Sablier run the recipient hook + ├── it should emit a {MetadataUpdate} event + └── it should emit a {WithdrawFromLockupStream} event diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol index 442e7be59..d064e9c3f 100644 --- a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -6,6 +6,7 @@ import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descript contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_GenerateAccentColor() external view { // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. + // Note: the address of `noop` depends on the order of the state variables in {Base_Test}. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); string memory expectedColor = "hsl(302,69%,44%)"; assertEq(actualColor, expectedColor, "accentColor"); diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 4f7abddc9..16fc0b538 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -91,7 +91,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is whenCliffTimeNotInTheFuture { vm.assume(depositAmount != 0); - timeWarp0 = boundUint40(timeWarp0, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1); + timeWarp0 = boundUint40(timeWarp0, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); timeWarp1 = boundUint40(timeWarp1, timeWarp0, defaults.TOTAL_DURATION()); // Mint enough assets to the Sender. diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/integration/fuzz/lockup/cancel.t.sol index 3597ba4bb..532e47b6d 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/integration/fuzz/lockup/cancel.t.sol @@ -52,15 +52,20 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ whenCallerAuthorized givenStreamCancelable givenStatusStreaming - givenRecipientContract - givenRecipientImplementsHook - whenRecipientDoesNotRevert - whenNoRecipientReentrancy + givenRecipientAllowedToHook + whenRecipientNotReverting + whenRecipientReturnsSelector + whenRecipientNotReentrant { - timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1); + timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); + + // Allow the recipient to hook. + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + resetPrank({ msgSender: users.sender }); // Create the stream. - uint256 streamId = createDefaultStreamWithRecipient(address(goodRecipient)); + uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); @@ -71,7 +76,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ // Make the withdrawal only if the amount is greater than zero. if (withdrawAmount > 0) { - lockup.withdraw({ streamId: streamId, to: address(goodRecipient), amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); } // Expect the assets to be refunded to the Sender. @@ -81,7 +86,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ // Expect the relevant events to be emitted. uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); vm.expectEmit({ emitter: address(lockup) }); - emit CancelLockupStream(streamId, users.sender, address(goodRecipient), dai, senderAmount, recipientAmount); + emit CancelLockupStream(streamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); @@ -99,7 +104,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ // Assert that the NFT has not been burned. address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = address(goodRecipient); + address expectedNFTOwner = address(recipientGood); assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/integration/shared/lockup/cancel.t.sol b/test/integration/shared/lockup/cancel.t.sol index a6f947bcd..da2a1563e 100644 --- a/test/integration/shared/lockup/cancel.t.sol +++ b/test/integration/shared/lockup/cancel.t.sol @@ -15,16 +15,12 @@ abstract contract Cancel_Integration_Shared_Test is Lockup_Integration_Shared_Te _; } - modifier givenRecipientContract() { + modifier givenRecipientAllowedToHook() { _; } - modifier givenRecipientImplementsHook() { - _; - } - - /// @dev In the LockupLinear contract, the streaming starts after the cliff time, whereas in the LockupDynamic - /// contract, the streaming starts after the start time. + /// @dev In LockupLinear, the streaming starts after the cliff time, whereas in LockupDynamic, the streaming starts + /// after the start time. modifier givenStatusStreaming() { // Warp to the future, after the stream's start time but before the stream's end time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -51,15 +47,19 @@ abstract contract Cancel_Integration_Shared_Test is Lockup_Integration_Shared_Te _; } - modifier whenNoRecipientReentrancy() { + modifier whenNotDelegateCalled() { + _; + } + + modifier whenRecipientNotReentrant() { _; } - modifier whenNotDelegateCalled() { + modifier whenRecipientNotReverting() { _; } - modifier whenRecipientDoesNotRevert() { + modifier whenRecipientReturnsSelector() { _; } } diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/integration/shared/lockup/withdraw.t.sol index dd2f968fc..75fe7fa5e 100644 --- a/test/integration/shared/lockup/withdraw.t.sol +++ b/test/integration/shared/lockup/withdraw.t.sol @@ -11,15 +11,17 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ resetPrank({ msgSender: users.recipient }); } - modifier givenNotNull() { + modifier givenEndTimeInTheFuture() { + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); _; } - modifier givenRecipientContract() { + modifier givenNotNull() { _; } - modifier givenSenderContract() { + modifier givenRecipientAllowedToHook() { _; } @@ -32,6 +34,11 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } + modifier whenCallerSender() { + resetPrank({ msgSender: users.sender }); + _; + } + modifier whenNoOverdraw() { _; } @@ -40,6 +47,18 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ _; } + modifier whenRecipientNotReentrant() { + _; + } + + modifier whenRecipientNotReverting() { + _; + } + + modifier whenRecipientReturnsSelector() { + _; + } + modifier whenStreamHasNotBeenCanceled() { _; } diff --git a/test/mocks/Hooks.sol b/test/mocks/Hooks.sol new file mode 100644 index 000000000..99d3a7c00 --- /dev/null +++ b/test/mocks/Hooks.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; + +import { ISablierLockupRecipient } from "../../src/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "../../src/interfaces/ISablierV2Lockup.sol"; + +contract RecipientGood is ISablierLockupRecipient, ERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(ISablierLockupRecipient).interfaceId; + } + + function onSablierLockupCancel( + uint256 streamId, + address sender, + uint128 senderAmount, + uint128 recipientAmount + ) + external + pure + override + returns (bytes4) + { + streamId; + sender; + senderAmount; + recipientAmount; + + return ISablierLockupRecipient.onSablierLockupCancel.selector; + } + + function onSablierLockupWithdraw( + uint256 streamId, + address caller, + address to, + uint128 amount + ) + external + pure + override + returns (bytes4) + { + streamId; + caller; + to; + amount; + + return ISablierLockupRecipient.onSablierLockupWithdraw.selector; + } +} + +contract RecipientInterfaceIDIncorrect is ISablierLockupRecipient, ERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == 0xffffffff; + } + + function onSablierLockupCancel(uint256, address, uint128, uint128) external pure override returns (bytes4) { + return ISablierLockupRecipient.onSablierLockupCancel.selector; + } + + function onSablierLockupWithdraw(uint256, address, address, uint128) external pure override returns (bytes4) { + return ISablierLockupRecipient.onSablierLockupWithdraw.selector; + } +} + +contract RecipientInterfaceIDMissing { + function onSablierLockupCancel(uint256, address, uint128, uint128) external pure returns (bytes4) { + return ISablierLockupRecipient.onSablierLockupCancel.selector; + } + + function onSablierLockupWithdraw(uint256, address, address, uint128) external pure returns (bytes4) { + return ISablierLockupRecipient.onSablierLockupWithdraw.selector; + } +} + +contract RecipientInvalidSelector is ISablierLockupRecipient, ERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(ISablierLockupRecipient).interfaceId; + } + + function onSablierLockupCancel( + uint256 streamId, + address sender, + uint128 senderAmount, + uint128 recipientAmount + ) + external + pure + override + returns (bytes4) + { + streamId; + sender; + senderAmount; + recipientAmount; + + return 0x10000000; + } + + function onSablierLockupWithdraw( + uint256 streamId, + address caller, + address to, + uint128 amount + ) + external + pure + override + returns (bytes4) + { + streamId; + caller; + to; + amount; + + return 0x12345678; + } +} + +contract RecipientReentrant is ISablierLockupRecipient, ERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(ISablierLockupRecipient).interfaceId; + } + + function onSablierLockupCancel( + uint256 streamId, + address sender, + uint128 senderAmount, + uint128 recipientAmount + ) + external + override + returns (bytes4) + { + streamId; + sender; + senderAmount; + recipientAmount; + + ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), recipientAmount); + + return ISablierLockupRecipient.onSablierLockupCancel.selector; + } + + function onSablierLockupWithdraw( + uint256 streamId, + address caller, + address to, + uint128 amount + ) + external + override + returns (bytes4) + { + streamId; + caller; + to; + amount; + + ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), amount); + + return ISablierLockupRecipient.onSablierLockupWithdraw.selector; + } +} + +contract RecipientReverting is ISablierLockupRecipient, ERC165 { + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(ISablierLockupRecipient).interfaceId; + } + + function onSablierLockupCancel( + uint256 streamId, + address sender, + uint128 senderAmount, + uint128 recipientAmount + ) + external + pure + override + returns (bytes4) + { + streamId; + sender; + senderAmount; + recipientAmount; + revert("You shall not pass"); + } + + function onSablierLockupWithdraw( + uint256 streamId, + address caller, + address to, + uint128 amount + ) + external + pure + override + returns (bytes4) + { + streamId; + caller; + to; + amount; + revert("You shall not pass"); + } +} diff --git a/test/mocks/hooks/GoodRecipient.sol b/test/mocks/hooks/GoodRecipient.sol deleted file mode 100644 index a2601e679..000000000 --- a/test/mocks/hooks/GoodRecipient.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; - -contract GoodRecipient is ISablierV2Recipient { - function onLockupStreamCanceled( - uint256 streamId, - address sender, - uint128 senderAmount, - uint128 recipientAmount - ) - external - pure - { - streamId; - sender; - senderAmount; - recipientAmount; - } - - function onLockupStreamRenounced(uint256 streamId) external pure { - streamId; - } - - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { - streamId; - caller; - to; - amount; - } -} diff --git a/test/mocks/hooks/GoodSender.sol b/test/mocks/hooks/GoodSender.sol deleted file mode 100644 index 564d3cc07..000000000 --- a/test/mocks/hooks/GoodSender.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; - -contract GoodSender is ISablierV2Sender { - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { - streamId; - caller; - to; - amount; - } -} diff --git a/test/mocks/hooks/ReentrantRecipient.sol b/test/mocks/hooks/ReentrantRecipient.sol deleted file mode 100644 index 567b486e9..000000000 --- a/test/mocks/hooks/ReentrantRecipient.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; - -contract ReentrantRecipient is ISablierV2Recipient { - function onLockupStreamCanceled( - uint256 streamId, - address sender, - uint128 senderAmount, - uint128 recipientAmount - ) - external - { - streamId; - senderAmount; - sender; - recipientAmount; - ISablierV2Lockup(msg.sender).cancel(streamId); - } - - function onLockupStreamRenounced(uint256 streamId) external { - ISablierV2Lockup(msg.sender).renounce(streamId); - } - - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external { - streamId; - caller; - to; - amount; - ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), amount); - } -} diff --git a/test/mocks/hooks/ReentrantSender.sol b/test/mocks/hooks/ReentrantSender.sol deleted file mode 100644 index ab10c75eb..000000000 --- a/test/mocks/hooks/ReentrantSender.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Lockup } from "../../../src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; - -contract ReentrantSender is ISablierV2Sender { - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external { - streamId; - caller; - to; - amount; - ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), amount); - } -} diff --git a/test/mocks/hooks/RevertingRecipient.sol b/test/mocks/hooks/RevertingRecipient.sol deleted file mode 100644 index 339ce281a..000000000 --- a/test/mocks/hooks/RevertingRecipient.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Recipient } from "../../../src/interfaces/hooks/ISablierV2Recipient.sol"; - -contract RevertingRecipient is ISablierV2Recipient { - function onLockupStreamCanceled( - uint256 streamId, - address sender, - uint128 senderAmount, - uint128 recipientAmount - ) - external - pure - { - streamId; - sender; - senderAmount; - recipientAmount; - revert("You shall not pass"); - } - - function onLockupStreamRenounced(uint256 streamId) external pure { - streamId; - revert("You shall not pass"); - } - - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { - streamId; - caller; - to; - amount; - revert("You shall not pass"); - } -} diff --git a/test/mocks/hooks/RevertingSender.sol b/test/mocks/hooks/RevertingSender.sol deleted file mode 100644 index 98f47ce97..000000000 --- a/test/mocks/hooks/RevertingSender.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ISablierV2Sender } from "../../../src/interfaces/hooks/ISablierV2Sender.sol"; - -contract RevertingSender is ISablierV2Sender { - function onLockupStreamWithdrawn(uint256 streamId, address caller, address to, uint128 amount) external pure { - streamId; - caller; - to; - amount; - revert("You shall not pass"); - } -} diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 9822f1a7b..21e959781 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -32,6 +32,8 @@ abstract contract Events { SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ + event AllowToHook(address admin, address recipient); + event CancelLockupStream( uint256 streamId, address indexed sender, From 3ee63dbeb570b133eb4095e211a5e736704c144c Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 27 Jun 2024 16:43:20 +0300 Subject: [PATCH 122/132] test: benchmarks polish (#954) * test: rename variables * docs: wording improvement --- benchmark/Benchmark.t.sol | 21 +++++++++------------ src/libraries/Errors.sol | 4 ++-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol index 94417c9bf..78856032f 100644 --- a/benchmark/Benchmark.t.sol +++ b/benchmark/Benchmark.t.sol @@ -22,6 +22,7 @@ abstract contract Benchmark_Test is Base_Test { /// @dev The path to the file where the benchmark results are stored. string internal benchmarkResultsFile; + /// @dev A variable used to store the content to append to the results file. string internal contentToAppend; ISablierV2Lockup internal lockup; @@ -52,10 +53,9 @@ abstract contract Benchmark_Test is Base_Test { lockup.withdrawMax(streamIds[0], users.recipient); - uint256 beforeGas = gasleft(); + uint256 initialGas = gasleft(); lockup.burn(streamIds[0]); - - string memory gasUsed = vm.toString(beforeGas - gasleft()); + string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat("| `burn` | ", gasUsed, " |"); @@ -67,10 +67,9 @@ abstract contract Benchmark_Test is Base_Test { // Set the caller to the Sender for the next calls and change timestamp to before end time resetPrank({ msgSender: users.sender }); - uint256 beforeGas = gasleft(); + uint256 initialGas = gasleft(); lockup.cancel(streamIds[1]); - - string memory gasUsed = vm.toString(beforeGas - gasleft()); + string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat("| `cancel` | ", gasUsed, " |"); @@ -82,10 +81,9 @@ abstract contract Benchmark_Test is Base_Test { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); - uint256 beforeGas = gasleft(); + uint256 initialGas = gasleft(); lockup.renounce(streamIds[2]); - - string memory gasUsed = vm.toString(beforeGas - gasleft()); + string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat("| `renounce` | ", gasUsed, " |"); @@ -98,10 +96,9 @@ abstract contract Benchmark_Test is Base_Test { uint128 withdrawAmount = lockup.withdrawableAmountOf(streamId); - uint256 beforeGas = gasleft(); + uint256 initialGas = gasleft(); lockup.withdraw(streamId, to, withdrawAmount); - - string memory gasUsed = vm.toString(beforeGas - gasleft()); + string memory gasUsed = vm.toString(initialGas - gasleft()); // Check if caller is recipient or not. bool isCallerRecipient = caller == users.recipient; diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 9115a0274..03e6c8e05 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -21,10 +21,10 @@ library Errors { SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ - /// @notice Thrown when trying to allow for hook a contract that doesn't implement the interface correctly. + /// @notice Thrown when trying to allow to hook a contract that doesn't implement the interface correctly. error SablierV2Lockup_AllowToHookUnsupportedInterface(address recipient); - /// @notice Thrown when trying to allow for hook an address with no code. + /// @notice Thrown when trying to allow to hook an address with no code. error SablierV2Lockup_AllowToHookZeroCodeSize(address recipient); /// @notice Thrown when the broker fee exceeds the maximum allowed fee. From 73b2d8043cd8aac48f92ccd49ef77dc3498629ed Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 29 Jun 2024 15:18:45 +0100 Subject: [PATCH 123/132] test: fix revert error in test_RevertWhen_LoopCalculationOverflowsBlockGasLimit --- .../lockup-dynamic/create-with-deltas/createWithDeltas.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol b/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol index cd79d99a4..6246731f3 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-deltas/createWithDeltas.t.sol @@ -33,8 +33,8 @@ contract CreateWithDeltas_LockupDynamic_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_LoopCalculationOverflowsBlockGasLimit() external whenNotDelegateCalled { - LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](250_000); - vm.expectRevert(bytes("")); + LockupDynamic.SegmentWithDelta[] memory segments = new LockupDynamic.SegmentWithDelta[](25_000); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, 25_000)); createDefaultStreamWithDeltas(segments); } From c05bfd60d2c259773eb63bbcf82ca8bf398690c3 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 29 Jun 2024 16:13:27 +0100 Subject: [PATCH 124/132] test: keep gas usage below foundry 1B limit (#957) --- .../createWithDurations.t.sol | 18 +++++++----------- .../createWithDurations.tree | 4 ++-- .../createWithDurations.t.sol | 16 ++++++---------- .../createWithDurations.tree | 4 ++-- .../lockup-dynamic/createWithDurations.t.sol | 2 +- .../lockup-dynamic/createWithTimestamps.t.sol | 2 +- .../lockup-tranched/createWithDurations.t.sol | 2 +- .../shared/lockup/createWithDurations.t.sol | 8 ++++++-- 8 files changed, 26 insertions(+), 30 deletions(-) diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 878150cba..4edb555f3 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -33,17 +33,13 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is } /// @dev it should revert. - function test_RevertWhen_LoopCalculationOverflowsBlockGasLimit() external whenNotDelegateCalled { - LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](250_000); - vm.expectRevert(bytes("")); + function test_RevertWhen_SegmentCountTooHigh() external whenNotDelegateCalled { + LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](25_000); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, 25_000)); createDefaultStreamWithDurations(segments); } - function test_RevertWhen_DurationsZero() - external - whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit - { + function test_RevertWhen_DurationsZero() external whenNotDelegateCalled whenSegmentCountNotTooHigh { uint40 startTime = getBlockTimestamp(); LockupDynamic.SegmentWithDuration[] memory segments = defaults.createWithDurationsLD().segments; segments[1].duration = 0; @@ -62,7 +58,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is function test_RevertWhen_TimestampsCalculationsOverflows_StartTimeNotLessThanFirstSegmentTimestamp() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenSegmentCountNotTooHigh whenDurationsNotZero { unchecked { @@ -83,7 +79,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is function test_RevertWhen_TimestampsCalculationsOverflows_SegmentTimestampsNotOrdered() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenSegmentCountNotTooHigh whenDurationsNotZero { unchecked { @@ -118,7 +114,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is function test_CreateWithDurations() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenSegmentCountNotTooHigh whenDurationsNotZero whenTimestampsCalculationsDoNotOverflow { diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree index 9c42b9b8a..fa917579a 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree @@ -2,9 +2,9 @@ createWithDurations.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── when the loop calculations overflow the block gas limit + ├── when the segment count is too high │ └── it should revert - └── when the loop calculations do not overflow the block gas limit + └── when the segment count is not too high ├── when at least one of the durations at index one or greater is zero │ └── it should revert └── when none of the durations is zero diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 32d71c6b3..9db841bb2 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -31,17 +31,13 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is } /// @dev it should revert. - function test_RevertWhen_LoopCalculationOverflowsBlockGasLimit() external whenNotDelegateCalled { + function test_RevertWhen_TrancheCountTooHigh() external whenNotDelegateCalled { LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](25_000); - vm.expectRevert(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, 25_000)); createDefaultStreamWithDurations(tranches); } - function test_RevertWhen_DurationsZero() - external - whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit - { + function test_RevertWhen_DurationsZero() external whenNotDelegateCalled whenTrancheCountNotTooHigh { uint40 startTime = getBlockTimestamp(); LockupTranched.TrancheWithDuration[] memory tranches = defaults.createWithDurationsLT().tranches; tranches[2].duration = 0; @@ -60,7 +56,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is function test_RevertWhen_TimestampsCalculationsOverflows_StartTimeNotLessThanFirstTrancheTimestamp() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenTrancheCountNotTooHigh whenDurationsNotZero { unchecked { @@ -81,7 +77,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is function test_RevertWhen_TimestampsCalculationsOverflows_TrancheTimestampsNotOrdered() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenTrancheCountNotTooHigh whenDurationsNotZero { unchecked { @@ -112,7 +108,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is function test_CreateWithDurations() external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenTrancheCountNotTooHigh whenDurationsNotZero whenTimestampsCalculationsDoNotOverflow { diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree index e4b379b65..d3f633068 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree +++ b/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree @@ -2,9 +2,9 @@ createWithDurations.t.sol ├── when delegate called │ └── it should revert └── when not delegate called - ├── when the loop calculations overflow the block gas limit + ├── when the tranche count is too high │ └── it should revert - └── when the loop calculations do not overflow the block gas limit + └── when the tranche count is not too high ├── when at least one of the durations at index one or greater is zero │ └── it should revert └── when none of the durations is zero diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index bb5b9b334..4bf6242b4 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -37,7 +37,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenSegmentCountNotTooHigh whenDurationsNotZero whenTimestampsCalculationsDoNotOverflow { diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 44cfe385a..6b55b5d07 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -31,7 +31,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentCountNotZero { uint256 defaultMax = defaults.MAX_SEGMENT_COUNT(); - segmentCount = _bound(segmentCount, defaultMax + 1, defaultMax * 10); + segmentCount = _bound(segmentCount, defaultMax + 1, defaultMax * 2); LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol index c70594e0b..10bb043d1 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -37,7 +37,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is function testFuzz_CreateWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) external whenNotDelegateCalled - whenLoopCalculationsDoNotOverflowBlockGasLimit + whenTrancheCountNotTooHigh whenDurationsNotZero whenTimestampsCalculationsDoNotOverflow { diff --git a/test/integration/shared/lockup/createWithDurations.t.sol b/test/integration/shared/lockup/createWithDurations.t.sol index 8446dc2c3..8a2acdc20 100644 --- a/test/integration/shared/lockup/createWithDurations.t.sol +++ b/test/integration/shared/lockup/createWithDurations.t.sol @@ -18,11 +18,11 @@ abstract contract CreateWithDurations_Integration_Shared_Test is Lockup_Integrat _; } - modifier whenLoopCalculationsDoNotOverflowBlockGasLimit() { + modifier whenNotDelegateCalled() { _; } - modifier whenNotDelegateCalled() { + modifier whenSegmentCountNotTooHigh() { _; } @@ -33,4 +33,8 @@ abstract contract CreateWithDurations_Integration_Shared_Test is Lockup_Integrat modifier whenTotalDurationCalculationDoesNotOverflow() { _; } + + modifier whenTrancheCountNotTooHigh() { + _; + } } From cf2c46a206dc67a2280c9e98b53591e6de0ee504 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Sat, 29 Jun 2024 23:26:14 +0300 Subject: [PATCH 125/132] perf: return 0 in linear when startTime == blockTimestamp (#959) --- precompiles/Precompiles.sol | 2 +- src/SablierV2LockupLinear.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index bbfe99e4f..f4baef6f7 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -28,7 +28,7 @@ contract Precompiles { bytes public constant BYTECODE_LOCKUP_DYNAMIC = hex"60c0604052346103e457615a426060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615634908161040e823960805181613927015260a051818181610bbf01526139f10152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127be57508063027b67441461279c57806306fdde03146126e1578063081812fc146126c3578063095ea7b3146125be5780631400ecec1461250d5780631c1cdd4c146124a95780631e99d5691461248c57806323b872dd14612475578063303acc851461243857806331df3d4814612325578063406887cb146121b357806340e58ee514611e9a578063425d30dd14611e4a57806342842e0e14611e2157806342966c6814611c5d5780634426757014611c375780634857501f14611bc65780634869e12d14611b8c5780634cc55e1114611a9457806354c02292146117e357806357404b12146117555780636352211e146117265780636d0cee751461172657806370a08231146116bc57806375829def1461164e5780637cad6cd11461155d5780637de6b1db146113de5780638659c27014610fe0578063894e9a0d14610cb15780638f69b99314610c315780639067b67714610be25780639188ec8414610ba857806395d89b4114610aa0578063a22cb465146109ec578063a80fc0711461099b578063ad35efd41461093c578063b2564569146108ec578063b637b86514610893578063b88d4fde1461080b578063b8a3be66146107d6578063b971302a14610788578063bc2be1be14610739578063c156a11d14610609578063c87b56dd146104f3578063d4dbd20b146104a2578063d511609f14610457578063d975dfed1461040c578063e985e9c5146103b3578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128eb565b6044356001600160801b03811681036102b0576102ae916102a661391d565b6004356133d1565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b0576102ae6004356103a46128eb565b6103ad826141f8565b91613062565b346102b05760403660031901126102b0576103cc6128d5565b6001600160a01b036103dc6128eb565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576104466020916141f8565b6001600160801b0360405191168152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b0576004356105108161369f565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156105fe575f90610581575b61057d906040519182916020835260208301906128b0565b0390f35b503d805f833e6105918183612a6e565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105c983612a90565b916105d76040519384612a6e565b838352602084830101116102b05761057d926105f9916020808501910161288f565b610565565b6040513d5f823e3d90fd5b346102b05760403660031901126102b0576004356106256128eb565b9061062e61391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f5260036020526001600160a01b0360405f2054169182330361071957610670826141f8565b6001600160801b038116610708575b506001600160a01b038116156106f5576106a1826001600160a01b03926137e3565b1691826106bb5750637e27328960e01b5f5260045260245ffd5b8083036106c457005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610713908484613062565b8361067f565b5063216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108246128d5565b61082c6128eb565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161085983612a90565b926108676040519485612a6e565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b60205261057d6108d860405f20612eeb565b604051918291602083526020830190612980565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576109749061374f565b6040516005821015610987576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a056128d5565b602435908115158092036102b0576001600160a01b0316908115610a7457335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610b9e575b602083108114610b8a57828552908115610b665750600114610b08575b61057d83610af481850382612a6e565b6040519182916020835260208301906128b0565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b4c57509091508101602001610af4610ae4565b919260018160209254838588010152019101909291610b34565b60ff191660208086019190915291151560051b84019091019150610af49050610ae4565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ac7565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c699061374f565b6005811015806109875760028214908115610ca5575b8115610c93575b6020826040519015158152f35b90506109875760046020911482610c86565b5050600381145f610c7f565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fcc57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d2c612e9b565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d6781612a51565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e06600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612eb9565b61012083019081526002610e198c61374f565b610e22816129f2565b14610fc4575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610e996101808d612a6e565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610eed90612eeb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057d91612980565b5f8752610e28565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101190369060040161294f565b9061101a61391d565b5f915b80831061102657005b611031838284612e2a565b359261103b61391d565b835f52600a60205260ff600160405f20015460a81c16156113cb57835f52600a60205260ff600160405f20015460a01c165f146110855783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113b9576110ba815f52600a6020526001600160a01b0360405f205416331490565b156113a3576110c8816136c0565b90805f52600a6020526110e0600260405f2001612eb9565b916001600160801b038351166001600160801b038216101561138f57815f52600a60205260ff60405f205460f01c161561137b57806001600160801b03602081611134948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611356575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061124f6001600160a01b03600160405f2001541694611227888588614652565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff611299866001600160a01b03165f52600960205260405f2090565b54166112af575b5050505050600101919061101d565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91611328575b50160361130c57808080806112a0565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611349915060203d811161134f575b6113418183612a6e565b81019061367f565b876112fc565b503d611337565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561117e565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b0576004356113fa61391d565b805f52600a60205260ff600160405f20015460a81c16156103235761141e8161374f565b611427816129f2565b600481036114425750634a5541ef60e01b5f5260045260245ffd5b61144b816129f2565b60038103611466575063fe19f19f60e01b5f5260045260245ffd5b600290611472816129f2565b1461154b57611495815f52600a6020526001600160a01b0360405f205416331490565b1561152c57805f52600a60205260ff60405f205460f01c161561151a576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611638575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116245760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116676128d5565b5f546001600160a01b03811633810361163857506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116dd6128d5565b1680156116fa575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174460043561369f565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b057600435611771612e83565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117bb83612a35565b825260208201526117e18251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761181e61391d565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b057611860913691612d46565b9081519161186d83612d2e565b9261187b6040519485612a6e565b808452601f1961188a82612d2e565b015f5b818110611a7d57505064ffffffffff4216916001600160801b036118b082613977565b51511667ffffffffffffffff60206118c784613977565b5101511664ffffffffff8060406118dd86613977565b5101511686011690604051926118f284612a19565b83526020830152604082015261190786613977565b5261191185613977565b5060015b8281106119e95750505061192b82600401612e62565b9261193860248401612e62565b9261194560448201612e4e565b916064820135936001600160a01b0385168095036102b0576020966119e1966119a1966001600160801b036119d6976001600160a01b0361198860848a01612e76565b948161199660a48c01612e76565b976040519d8e6129fc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612de3565b610100820152613998565b604051908152f35b806001600160801b036119fe60019385613984565b51511667ffffffffffffffff6020611a168487613984565b5101511664ffffffffff806040611a305f1987018d613984565b51015116816040611a41878a613984565b5101511601169060405192611a5584612a19565b835260208301526040820152611a6b8289613984565b52611a768188613984565b5001611915565b602090611a88612e9b565b8282890101520161188d565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ac590369060040161294f565b9060243567ffffffffffffffff81116102b057611ae690369060040161294f565b9091611af061391d565b818403611b5c575f5b848110611b0257005b80611b56611b136001938886612e2a565b35611b1f838987612e2a565b355f5260036020526001600160a01b0360405f205416611b48611b4385898b612e2a565b612e4e565b91611b5161391d565b6133d1565b01611af9565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610446602091614148565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611bff8261374f565b600581101561098757600203611c1d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c10565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c7961391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611df657611cb8816140d6565b156113a357805f5260036020526001600160a01b0360405f205416151580611def575b80611dd2575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d89575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d7757005b637e27328960e01b5f5260045260245ffd5b611da8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d2f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611ce1565b505f611cdb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3236612915565b9060405192611e42602085612a6e565b5f8452612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611eb661391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611eff57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113b957611f31815f52600a6020526001600160a01b0360405f205416331490565b1561152c57611f3f816136c0565b90805f52600a602052611f57600260405f2001612eb9565b916001600160801b038351166001600160801b03821610156121a057815f52600a60205260ff60405f205460f01c161561218d57806001600160801b03602081611fab948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612168575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061209e6001600160a01b03600160405f2001541694611227888588614652565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120e157005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91612149575b50160361213757005b632187e5e760e21b5f5260045260245ffd5b612162915060203d60201161134f576113418183612a6e565b8461212e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611ff5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121cc6128d5565b6001600160a01b035f54169033820361230e57806001600160a01b03913b156122e257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156105fe575f916122b3575b5015612288576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122d5915060203d6020116122db575b6122cd8183612a6e565b810190612e12565b8261223a565b503d6122c3565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761235f61391d565b6040519061236c826129fc565b61237881600401612901565b825261238660248201612901565b602083015261239760448201612aac565b604083015260648101356001600160a01b03811681036102b05760608301526123c2608482016129e5565b60808301526123d360a482016129e5565b60a08301526123e460c48201612d1c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119d66119e1926124286020953690602460048201359101612d46565b60e0840152610104369101612de3565b346102b05760203660031901126102b0576001600160a01b036124596128d5565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248636612915565b91612b02565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e19061374f565b6005811015610987578060209115908115612502575b506040519015158152f35b6001915014826124f7565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125a2575b612570575b506001600160801b0360405191168152f35b61259c9150805f52600a83526125966001600160801b03600260405f20015416916136c0565b90612ae2565b8261255e565b50805f52600a835260ff600160405f20015460a01c1615612559565b346102b05760403660031901126102b0576125d76128d5565b6024356125e38161369f565b331515806126b0575b8061267d575b6126515781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125f2565b50336001600160a01b03821614156125ec565b346102b05760203660031901126102b0576020611744600435612ac0565b346102b0575f3660031901126102b0576040515f6001548060011c90600181168015612792575b602083108114610b8a57828552908115610b6657506001146127345761057d83610af481850382612a6e565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061277857509091508101602001610af4610ae4565b919260018160209254838588010152019101909291612760565b91607f1691612708565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f49064906000000000000000000000000000000000000000000000000000000006020931490811561281a575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612865575b8115612854575b5083612813565b6301ffc9a760e01b9150148361284d565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612846565b5f5b8381106128a05750505f910152565b8181015183820152602001612891565b906020916128c98151809281855285808601910161288f565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b81811061299d5750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612990565b359081151582036102b057565b6005111561098757565b610120810190811067ffffffffffffffff821117610fcc57604052565b6060810190811067ffffffffffffffff821117610fcc57604052565b6040810190811067ffffffffffffffff821117610fcc57604052565b610140810190811067ffffffffffffffff821117610fcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610fcc57604052565b67ffffffffffffffff8111610fcc57601f01601f191660200190565b35906001600160801b03821682036102b057565b612ac98161369f565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162457565b91906001600160a01b031680156106f557815f5260036020526001600160a01b0360405f205416151580612d14575b80612cf7575b612ce4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2f575b6001600160a01b03935085612bf8575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036106c457505050565b612c17825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b97565b9192905080612c8d575b15612c4657828291612b87565b8284612c5e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cbb575b80612c395750825f526005602052336001600160a01b0360405f20541614612c39565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c98565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b37565b506001612b31565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fcc5760051b60200190565b929192612d5282612d2e565b93612d606040519586612a6e565b60606020868581520193028201918183116102b057925b828410612d845750505050565b6060848303126102b05760405190612d9b82612a19565b612da485612aac565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612dd360408801612d1c565b6040820152815201930192612d77565b91908260409103126102b057604051612dfb81612a35565b6020808294612e0981612901565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e3a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612e9082612a35565b5f6020838281520152565b60405190612ea882612a19565b5f6040838281528260208201520152565b90604051612ec681612a19565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612ef781612d2e565b92612f056040519485612a6e565b81845260208401905f5260205f205f915b838310612f235750505050565b600160208192604051612f3581612a19565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f16565b90612f7e838284612b02565b803b612f8b575b50505050565b602091612fd16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b0565b03815f865af15f9181613041575b5061300d5750612fed6141c9565b805190816130085782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361302f57505f808080612f85565b633250574960e11b5f5260045260245ffd5b61305b91925060203d60201161134f576113418183612a6e565b905f612fdf565b9061306b61391d565b815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f205416948583141580613344575b613310576001600160801b036130f7866141f8565b168085116132dd575061311c90855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561315f90612eb9565b6001600160801b036131838160208401511692826040818351169201511690612ae2565b1611156132ab575b835f52600a6020526131af836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613295575b6132195750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f91613276575b50160361213757808080612f85565b61328f915060203d60201161134f576113418183612a6e565b5f613267565b50835f52600960205260ff60405f20541661320f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561318b565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061334e856140d6565b156130e2565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f20541694858314158061366f575b613310576001600160801b0361345e866141f8565b168085116132dd575061348390855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134c690612eb9565b6001600160801b036134ea8160208401511692826040818351169201511690612ae2565b16111561363d575b835f52600a602052613516836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613618575b6135805750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f916135f9575b5016036135dd57808080612f85565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613612915060203d60201161134f576113418183612a6e565b5f6135ce565b5060ff613636856001600160a01b03165f52600960205260405f2090565b5416613576565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556134f2565b50613679856140d6565b15613449565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d77575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561374957815f52600a60205264ffffffffff60405f205460c81c16111561372e57805f52600b602052600160405f2054115f1461372557613722906142fe565b90565b6137229061423e565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137715750600490565b805f52600a60205260405f205460f81c6137dd57805f52600a60205264ffffffffff60405f205460a01c1642106137d8576137ab816136c0565b905f52600a6020526001600160801b0380600260405f200154169116105f146137d357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061390b575b806138ee575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138b7575b168061389f575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561385b565b6138d6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613854565b50805f52600a60205260ff600160405f20015460b01c1615613808565b506001600160a01b0382161515613802565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361394f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e3a5760200190565b8051821015612e3a5760209160051b010190565b906139ba6001600160801b036040840151166020610100850151015190614514565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140ae578015614086578151801561405e577f00000000000000000000000000000000000000000000000000000000000000008111614033575064ffffffffff6040613a2884613977565b51015116811015613fef57505f905f905f81515f905b808210613f67575050505064ffffffffff80421691169081811015613f395750506001600160801b031690818103613f0b57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c138751975f19890190613984565b51015160c81b169360a01b169116171785555f5b818110613dfd575050600187016007556001600160a01b0360208301511680156106f557613c5d886001600160a01b03926137e3565b16613dd1578682613cab6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145f1565b6001600160801b0360208401511680613da1575b506001600160a01b0381511694613d96613d786001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d1d8b612a35565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612980565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dcb906001600160a01b036060840151166001600160a01b0361010085015151169033906145f1565b5f613cbf565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e188160e0870151613984565b51825468010000000000000000811015610fcc5760018101808555811015612e3a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c27565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f8b906001600160801b03613f828588613984565b5151169061421e565b9364ffffffffff806040613f9f8685613984565b51015116941680851115613fbb57506001849301909291613a3e565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400084613977565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561411c575b508115614103575090565b90506001600160a01b036141173392612ac0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f8565b805f52600a60205261415f600260405f2001612eb9565b90805f52600a60205260ff600160405f20015460a01c165f1461418d5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ac5750613722906136c0565b61372291506001600160801b036040818351169201511690612ae2565b3d156141f3573d906141da82612a90565b916141e86040519384612a6e565b82523d5f602084013e565b606090565b6137229061420581614148565b905f52600a602052600260405f20015460801c90612ae2565b906001600160801b03809116911601906001600160801b03821161162457565b5f818152600a60205260409020546142759064ffffffffff60a082901c811660c89290921c811682900381169142821603166146a2565b90805f52600b60205260405f20805415612e3a575f526142ca67ffffffffffffffff60205f205460801c1692825f52600a6020526142c56001600160801b03600260405f20015416948592614782565b6147f5565b9182136142e757506142e36001600160801b03916148d0565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061432282612a51565b6101206143b560028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eb9565b92019182525f52600b6020526143cd60405f20612eeb565b915f9264ffffffffff60406143e183613977565b510151168664ffffffffff5f925b16106144d5578161446664ffffffffff9697988784816001600160801b0361441e6142c59861446b9b9a613984565b5151169a8b9867ffffffffffffffff6020614439868b613984565b510151169782604061444b8784613984565b5101511694806144b8575050511680925b03169203166146a2565b614782565b91821361448c5750906001600160801b0361448681936148d0565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b3575090565b905090565b60409250906144ca915f190190613984565b51015116809261445c565b936001600160801b03600191816144ec8886613984565b51511601169401958064ffffffffff8060406145088b87613984565b510151169892986143ef565b91909160405161452381612a35565b5f81525f6020820152926001600160801b0382169081156145d45767016345785d8a0000811161459d5761455f6001600160801b0391836154ed565b1660208501918183521115614589576001600160801b03918261458492511690612ae2565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e581612a35565b5f81525f602082015290565b9091926001600160a01b036146509481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261464b608483612a6e565b614905565b565b614650926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261464b606483612a6e565b600160ff1b81148015614775575b61474d575f811215614744576146d4815f035b5f84121561473d57835f039061498a565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470e575f19911813156147095790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061498a565b6146d4816146c3565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146b0565b8061479c575061479857670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e757806147bf575050670de0b6b3a764000090565b670de0b6b3a764000081146147e3576147de906142c561372293614a90565b614be7565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c3575b61489b575f81121561489257614827815f035b5f84121561488b57835f03906154ed565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485c575f19911813156147095790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ed565b61482781614816565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614803565b5f81126148da5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492e93169360208151910182865af16149276141c9565b908361559b565b805190811515918261496f575b50506149445750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149829250602080918301019101612e12565b155f8061493b565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a555781841015614a1b57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a62570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a62576ec097ce7bc90715b34b9f10000000000590565b805f811315614bbc57670de0b6b3a76400008112614b9c57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8957506706f05b59d3b20000905b5f8213614b535750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b7b575b60011d90614b46565b809192019160011d90614b72565b9050670de0b6b3a7640000929150020290565b5f1991508015614a62576ec097ce7bc90715b34b9f100000000005614aad565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c145768033dd1780914b971141981126137d857614c0b905f03614be7565b61372290614a76565b680a688906bd8affffff81136154c257670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538d575b670de0b6b3a76400009066ff000000000000831661527d575b65ff00000000008316615175575b64ff000000008316615075575b63ff0000008316614f7d575b62ff00008316614e8d575b61ff008316614da5575b60ff8316614cc5575b029060401c60bf031c90565b60808316614d92575b60408316614d7f575b60208316614d6c575b60108316614d59575b60088316614d46575b60048316614d33575b60028316614d20575b6001831615614cb957680100000000000000010260401c614cb9565b680100000000000000010260401c614d04565b680100000000000000030260401c614cfb565b680100000000000000060260401c614cf2565b6801000000000000000b0260401c614ce9565b680100000000000000160260401c614ce0565b6801000000000000002c0260401c614cd7565b680100000000000000590260401c614cce565b6180008316614e7a575b6140008316614e67575b6120008316614e54575b6110008316614e41575b6108008316614e2e575b6104008316614e1b575b6102008316614e08575b610100831615614cb057680100000000000000b10260401c614cb0565b680100000000000001630260401c614deb565b680100000000000002c60260401c614de1565b6801000000000000058c0260401c614dd7565b68010000000000000b170260401c614dcd565b6801000000000000162e0260401c614dc3565b68010000000000002c5d0260401c614db9565b680100000000000058b90260401c614daf565b628000008316614f6a575b624000008316614f57575b622000008316614f44575b621000008316614f31575b620800008316614f1e575b620400008316614f0b575b620200008316614ef8575b62010000831615614ca6576801000000000000b1720260401c614ca6565b680100000000000162e40260401c614eda565b6801000000000002c5c80260401c614ecf565b68010000000000058b910260401c614ec4565b680100000000000b17210260401c614eb9565b68010000000000162e430260401c614eae565b680100000000002c5c860260401c614ea3565b6801000000000058b90c0260401c614e98565b63800000008316615062575b6340000000831661504f575b6320000000831661503c575b63100000008316615029575b63080000008316615016575b63040000008316615003575b63020000008316614ff0575b6301000000831615614c9b5768010000000000b172180260401c614c9b565b6801000000000162e4300260401c614fd1565b68010000000002c5c8600260401c614fc5565b680100000000058b90c00260401c614fb9565b6801000000000b17217f0260401c614fad565b680100000000162e42ff0260401c614fa1565b6801000000002c5c85fe0260401c614f95565b68010000000058b90bfc0260401c614f89565b6480000000008316615162575b644000000000831661514f575b642000000000831661513c575b6410000000008316615129575b6408000000008316615116575b6404000000008316615103575b64020000000083166150f0575b640100000000831615614c8f57680100000000b17217f80260401c614c8f565b68010000000162e42ff10260401c6150d0565b680100000002c5c85fe30260401c6150c3565b6801000000058b90bfce0260401c6150b6565b68010000000b17217fbb0260401c6150a9565b6801000000162e42fff00260401c61509c565b68010000002c5c8601cc0260401c61508f565b680100000058b90c0b490260401c615082565b65800000000000831661526a575b654000000000008316615257575b652000000000008316615244575b651000000000008316615231575b65080000000000831661521e575b65040000000000831661520b575b6502000000000083166151f8575b65010000000000831615614c82576801000000b1721835510260401c614c82565b680100000162e430e5a20260401c6151d7565b6801000002c5c863b73f0260401c6151c9565b68010000058b90cf1e6e0260401c6151bb565b680100000b1721bcfc9a0260401c6151ad565b68010000162e43f4f8310260401c61519f565b680100002c5c89d5ec6d0260401c615191565b6801000058b91b5bc9ae0260401c615183565b6680000000000000831661537a575b66400000000000008316615367575b66200000000000008316615354575b66100000000000008316615341575b6608000000000000831661532e575b6604000000000000831661531b575b66020000000000008316615308575b6601000000000000831615614c745768010000b17255775c040260401c614c74565b6801000162e525ee05470260401c6152e6565b68010002c5cc37da94920260401c6152d7565b680100058ba01fb9f96d0260401c6152c8565b6801000b175effdc76ba0260401c6152b9565b680100162f3904051fa10260401c6152aa565b6801002c605e2e8cec500260401c61529b565b68010058c86da1c09ea20260401c61528c565b67800000000000000082166154a3575b670de0b6b3a7640000906740000000000000008316615490575b672000000000000000831661547d575b671000000000000000831661546a575b6708000000000000008316615457575b6704000000000000008316615444575b6702000000000000008316615431575b670100000000000000831661541e575b9050614c5b565b680100b1afa5abcbed610260401c615417565b68010163da9fb33356d80260401c615407565b680102c9a3e778060ee70260401c6153f7565b6801059b0d31585743ae0260401c6153e7565b68010b5586cf9890f62a0260401c6153d7565b6801172b83c7d517adce0260401c6153c7565b6801306fe0a31b7152df0260401c6153b7565b5077b504f333f9de64848000000000000000000000000000000061539d565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558a57670de0b6b3a764000082101561555a577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d857508051156155b057805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561e575b6155e9575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155e156fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614ac56040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146dc90816103e9823960805181613a300152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a557508063027b67441461308357806306fdde0314612fc8578063081812fc14612faa578063095ea7b314612ea55780631400ecec14612df45780631c1cdd4c14612d905780631e99d56914612d7357806323b872dd14612d5c578063303acc8514612d1f578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131d2565b90610288613334565b610290613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c85614270565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f2001613600565b6001600160801b036103b6816020840151169282604081835116920151169061336c565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f6565b810190613736565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a80565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131d2565b906106eb81614270565b6106f3613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f85614270565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f2001613600565b6001600160801b03610819816020840151169282604081835116920151169061336c565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f6565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a80565b1561076a565b346105f05760403660031901126105f0576109916131bc565b6001600160a01b036109a16131d2565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091614270565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613756565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613197565b0390f35b503d805f833e610b5681836132f6565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613318565b91610b9c60405193846132f6565b838352602084830101116105f057610b4292610bbe9160208085019101613176565b610b2a565b346105f05760403660031901126105f057600435610bdf6131d2565b90610be8613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c3283614270565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ec565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a26565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d4385614270565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f2001613600565b6001600160801b03610ddd816020840151169282604081835116920151169061336c565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614296565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f6565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a80565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131bc565b6110ba6131d2565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613318565b926110f560405194856132f6565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613646565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613858565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a26565b6111f46135e2565b64ffffffffff421680825264ffffffffff61120d613632565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613253565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132da565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b76565b604051908152f35b64ffffffffff611336613632565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131bc565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f6565b604051918291602083526020830190613197565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613858565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f610160604051611643816132a0565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135e2565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132bd565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c161515845201613600565b610120830190815261177187613858565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f7816132a0565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f057611938903690600401613222565b90611941613a26565b5f915b80831061194d57005b6119588382846135be565b3592611962613a26565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613777565b90805f52600a602052611a07600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b94818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614296565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f6565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a26565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613858565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131bc565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131bc565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613756565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135e2565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613284565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a26565b60405161211581613253565b61211d6131bc565b81526121276131d2565b6020820152612134613334565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613284565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132da565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b76565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b903690600401613222565b60243567ffffffffffffffff81116105f05761226b903690600401613222565b612276939193613a26565b8083036125b8575f5b83811061228857005b6122938185856135be565b3561229f8286866135be565b355f5260036020526001600160a01b0360405f205416906122c18385896135be565b356001600160801b038116908181036105f057506122dd613a26565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b0361235484614270565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f2001613600565b6001600160801b036123ee816020840151169282604081835116920151169061336c565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614296565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f6565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a80565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af2565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613858565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a80565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e8565b906040519261289d6020856132f6565b5f8452613646565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a26565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613777565b90805f52600a6020526129b2600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a0694818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614296565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131bc565b6001600160a01b035f541690338203612d0857806001600160a01b03913b15612cdc57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612cad575b5015612c82576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccf915060203d602011612cd5575b612cc781836132f6565b8101906135a6565b82612c34565b503d612cbd565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d406131bc565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6d366131e8565b9161338c565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc890613858565b60058110156111be578060209115908115612de9575b506040519015158152f35b600191501482612dde565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e89575b612e57575b506001600160801b0360405191168152f35b612e839150805f52600a8352612e7d6001600160801b03600260405f2001541691613777565b9061336c565b82612e45565b50805f52600a835260ff600160405f20015460a01c1615612e40565b346105f05760403660031901126105f057612ebe6131bc565b602435612eca81613756565b33151580612f97575b80612f64575b612f385781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed9565b50336001600160a01b0382161415612ed3565b346105f05760203660031901126105f057602061201860043561334a565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613079575b6020831081146115325782855290811561150e575060011461301b57610b428361149c818503826132f6565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305f5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613047565b91607f1691612fef565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f490649060000000000000000000000000000000000000000000000000000000060209314908115613101575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561314c575b811561313b575b50836130fa565b6301ffc9a760e01b91501483613134565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312d565b5f5b8381106131875750505f910152565b8181015183820152602001613178565b906020916131b081518092818552858086019101613176565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761327057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761327057604052565b610180810190811067ffffffffffffffff82111761327057604052565b610140810190811067ffffffffffffffff82111761327057604052565b6040810190811067ffffffffffffffff82111761327057604052565b90601f8019910116810190811067ffffffffffffffff82111761327057604052565b67ffffffffffffffff811161327057601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335381613756565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359e575b80613581575b61356e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b9575b6001600160a01b03935085613482575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b6134a1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613421565b9192905080613517575b156134d057828291613411565b82846134e857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613545575b806134c35750825f526005602052336001600160a01b0360405f205416146134c3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613522565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133c1565b5060016133bb565b908160209103126105f0575180151581036105f05790565b91908110156135ce5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ef82613284565b5f6040838281528260208201520152565b9060405161360d81613284565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061365283828461338c565b803b61365f575b50505050565b6020916136a56001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613197565b03815f865af15f9181613715575b506136e157506136c1614241565b805190816136dc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370357505f808080613659565b633250574960e11b5f5260045260245ffd5b61372f91925060203d6020116104f2576104e481836132f6565b905f6136b3565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384f575b61384957815f52600a60205264ffffffffff60405f205460c81c16908142101561382c57806137de9203904203614424565b815f52600a6020526138016001600160801b03600260405f200154168092614510565b908111613816576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281116137ac565b805f52600a60205260ff600160405f20015460a01c165f1461387a5750600490565b805f52600a60205260405f205460f81c6138e657805f52600a60205264ffffffffff60405f205460a01c1642106138e1576138b481613777565b905f52600a6020526001600160801b0380600260405f200154169116105f146138dc57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a14575b806139f7575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139c0575b16806139a8575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613964565b6139df835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395d565b50805f52600a60205260ff600160405f20015460b01c1615613911565b506001600160a01b038216151561390b565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5857565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac6575b508115613aad575090565b90506001600160a01b03613ac1339261334a565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa2565b805f52600a602052613b09600260405f2001613600565b90805f52600a60205260ff600160405f20015460a01c165f14613b375750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b595750613b5690613777565b90565b613b5691506001600160801b03604081835116920151169061336c565b90613b976001600160801b03604084015116602060e08501510151906142ed565b916001600160801b0383511660c082015190156142195764ffffffffff815116156141f1576020810164ffffffffff81511680614165575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413757505064ffffffffff80421691511690818110156141095750506007549280516001600160801b03169160405192613c2784613284565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8d896132bd565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0d91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140e9575b50600185016007556001600160a01b036020820151168015610cb357613f7b866001600160a01b03926138ec565b166140bd57613fa66001600160a01b036060830151166001600160801b0384511690309033906143ca565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408e575b506140856001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b7906001600160a01b036060880151166001600160a01b0360e089015151169033906143ca565b5f613fe1565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4d565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c357505064ffffffffff90511664ffffffffff60408301511690818110613bcf577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561426b573d9061425282613318565b9161426060405193846132f6565b82523d5f602084013e565b606090565b613b569061427d81613af2565b905f52600a602052600260405f20015460801c9061336c565b6142eb926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e66064836132f6565b6145be565b565b9190916040516142fc816132da565b5f81525f6020820152926001600160801b0382169081156143ad5767016345785d8a00008111614376576143386001600160801b039183614510565b1660208501918183521115614362576001600160801b03918261435d9251169061336c565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143be816132da565b5f81525f602082015290565b9091926001600160a01b036142eb9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e66084836132f6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144ef57818410156144b557670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fc570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ad57670de0b6b3a764000082101561457d577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e793169360208151910182865af16145e0614241565b9083614643565b8051908115159182614628575b50506145fd5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463b92506020809183010191016135a6565b155f806145f4565b90614680575080511561465857805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c6575b614691575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468956fea164736f6c634300081a000a"; + hex"60a0604052346103bf57614ac66040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146dd90816103e9823960805181613a310152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a557508063027b67441461308357806306fdde0314612fc8578063081812fc14612faa578063095ea7b314612ea55780631400ecec14612df45780631c1cdd4c14612d905780631e99d56914612d7357806323b872dd14612d5c578063303acc8514612d1f578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131d2565b90610288613334565b610290613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c85614271565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f2001613600565b6001600160801b036103b6816020840151169282604081835116920151169061336c565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f6565b810190613736565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a81565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131d2565b906106eb81614271565b6106f3613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f85614271565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f2001613600565b6001600160801b03610819816020840151169282604081835116920151169061336c565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f6565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a81565b1561076a565b346105f05760403660031901126105f0576109916131bc565b6001600160a01b036109a16131d2565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091614271565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613756565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613197565b0390f35b503d805f833e610b5681836132f6565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613318565b91610b9c60405193846132f6565b838352602084830101116105f057610b4292610bbe9160208085019101613176565b610b2a565b346105f05760403660031901126105f057600435610bdf6131d2565b90610be8613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c3283614271565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ed565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a27565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d4385614271565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f2001613600565b6001600160801b03610ddd816020840151169282604081835116920151169061336c565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614297565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f6565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a81565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131bc565b6110ba6131d2565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613318565b926110f560405194856132f6565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613646565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613859565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a27565b6111f46135e2565b64ffffffffff421680825264ffffffffff61120d613632565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613253565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132da565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b77565b604051908152f35b64ffffffffff611336613632565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131bc565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f6565b604051918291602083526020830190613197565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613859565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f610160604051611643816132a0565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135e2565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132bd565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c161515845201613600565b610120830190815261177187613859565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f7816132a0565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f057611938903690600401613222565b90611941613a27565b5f915b80831061194d57005b6119588382846135be565b3592611962613a27565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613777565b90805f52600a602052611a07600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b94818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614297565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f6565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a27565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613859565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131bc565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131bc565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613756565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135e2565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613284565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a27565b60405161211581613253565b61211d6131bc565b81526121276131d2565b6020820152612134613334565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613284565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132da565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b77565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b903690600401613222565b60243567ffffffffffffffff81116105f05761226b903690600401613222565b612276939193613a27565b8083036125b8575f5b83811061228857005b6122938185856135be565b3561229f8286866135be565b355f5260036020526001600160a01b0360405f205416906122c18385896135be565b356001600160801b038116908181036105f057506122dd613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b0361235484614271565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f2001613600565b6001600160801b036123ee816020840151169282604081835116920151169061336c565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f6565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a81565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af3565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613859565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a81565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e8565b906040519261289d6020856132f6565b5f8452613646565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613777565b90805f52600a6020526129b2600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a0694818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614297565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131bc565b6001600160a01b035f541690338203612d0857806001600160a01b03913b15612cdc57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612cad575b5015612c82576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccf915060203d602011612cd5575b612cc781836132f6565b8101906135a6565b82612c34565b503d612cbd565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d406131bc565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6d366131e8565b9161338c565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc890613859565b60058110156111be578060209115908115612de9575b506040519015158152f35b600191501482612dde565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e89575b612e57575b506001600160801b0360405191168152f35b612e839150805f52600a8352612e7d6001600160801b03600260405f2001541691613777565b9061336c565b82612e45565b50805f52600a835260ff600160405f20015460a01c1615612e40565b346105f05760403660031901126105f057612ebe6131bc565b602435612eca81613756565b33151580612f97575b80612f64575b612f385781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed9565b50336001600160a01b0382161415612ed3565b346105f05760203660031901126105f057602061201860043561334a565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613079575b6020831081146115325782855290811561150e575060011461301b57610b428361149c818503826132f6565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305f5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613047565b91607f1691612fef565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f490649060000000000000000000000000000000000000000000000000000000060209314908115613101575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561314c575b811561313b575b50836130fa565b6301ffc9a760e01b91501483613134565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312d565b5f5b8381106131875750505f910152565b8181015183820152602001613178565b906020916131b081518092818552858086019101613176565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761327057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761327057604052565b610180810190811067ffffffffffffffff82111761327057604052565b610140810190811067ffffffffffffffff82111761327057604052565b6040810190811067ffffffffffffffff82111761327057604052565b90601f8019910116810190811067ffffffffffffffff82111761327057604052565b67ffffffffffffffff811161327057601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335381613756565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359e575b80613581575b61356e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b9575b6001600160a01b03935085613482575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b6134a1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613421565b9192905080613517575b156134d057828291613411565b82846134e857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613545575b806134c35750825f526005602052336001600160a01b0360405f205416146134c3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613522565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133c1565b5060016133bb565b908160209103126105f0575180151581036105f05790565b91908110156135ce5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ef82613284565b5f6040838281528260208201520152565b9060405161360d81613284565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061365283828461338c565b803b61365f575b50505050565b6020916136a56001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613197565b03815f865af15f9181613715575b506136e157506136c1614242565b805190816136dc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370357505f808080613659565b633250574960e11b5f5260045260245ffd5b61372f91925060203d6020116104f2576104e481836132f6565b905f6136b3565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384f575b61384957815f52600a60205264ffffffffff60405f205460c81c16908142101561382c57806137de9203904203614425565b815f52600a6020526138016001600160801b03600260405f200154168092614511565b908111613816576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b50428110156137ac565b805f52600a60205260ff600160405f20015460a01c165f1461387b5750600490565b805f52600a60205260405f205460f81c6138e757805f52600a60205264ffffffffff60405f205460a01c1642106138e2576138b581613777565b905f52600a6020526001600160801b0380600260405f200154169116105f146138dd57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a15575b806139f8575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139c1575b16806139a9575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613965565b6139e0835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395e565b50805f52600a60205260ff600160405f20015460b01c1615613912565b506001600160a01b038216151561390c565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5957565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac7575b508115613aae575090565b90506001600160a01b03613ac2339261334a565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa3565b805f52600a602052613b0a600260405f2001613600565b90805f52600a60205260ff600160405f20015460a01c165f14613b385750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b5a5750613b5790613777565b90565b613b5791506001600160801b03604081835116920151169061336c565b90613b986001600160801b03604084015116602060e08501510151906142ee565b916001600160801b0383511660c0820151901561421a5764ffffffffff815116156141f2576020810164ffffffffff81511680614166575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413857505064ffffffffff804216915116908181101561410a5750506007549280516001600160801b03169160405192613c2884613284565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8e896132bd565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0e91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140ea575b50600185016007556001600160a01b036020820151168015610cb357613f7c866001600160a01b03926138ed565b166140be57613fa76001600160a01b036060830151166001600160801b0384511690309033906143cb565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408f575b506140866001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b8906001600160a01b036060880151166001600160a01b0360e089015151169033906143cb565b5f613fe2565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4e565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c457505064ffffffffff90511664ffffffffff60408301511690818110613bd0577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561426c573d9061425382613318565b9161426160405193846132f6565b82523d5f602084013e565b606090565b613b579061427e81613af3565b905f52600a602052600260405f20015460801c9061336c565b6142ec926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e76064836132f6565b6145bf565b565b9190916040516142fd816132da565b5f81525f6020820152926001600160801b0382169081156143ae5767016345785d8a00008111614377576143396001600160801b039183614511565b1660208501918183521115614363576001600160801b03918261435e9251169061336c565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143bf816132da565b5f81525f602082015290565b9091926001600160a01b036142ec9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e76084836132f6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144f057818410156144b657670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fd570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ae57670de0b6b3a764000082101561457e577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e893169360208151910182865af16145e1614242565b9083614644565b8051908115159182614629575b50506145fe5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463c92506020809183010191016135a6565b155f806145f5565b90614681575080511561465957805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c7575b614692575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468a56fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c0604052346103e457614da86060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600160075561499a908161040e823960805181613dac015260a051818181612f330152613e550152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461329f57508063027b67441461327d57806306fdde03146131c2578063081812fc146131a4578063095ea7b31461309f5780631400ecec14612fee5780631c1cdd4c14612f8a5780631e99d56914612f6d57806323b872dd14612f565780632fe4304114612f1c578063303acc8514612edf57806332fbe22b14612d82578063406887cb14612c1057806340e58ee514612958578063425d30dd1461290857806342842e0e146128df57806342966c681461271b57806344267570146126f55780634857501f146126845780634869e12d1461264a5780634cc55e111461229157806357404b12146122035780636352211e146121d45780636d0cee75146121d457806370a082311461216a57806375829def146120fc5780637cad6cd11461200b5780637de6b1db14611ebe5780637f5799f914611e655780638659c27014611aae578063894e9a0d1461176f578063897f362b146114a45780638f69b993146114245780639067b677146113d557806395d89b41146112cd578063a22cb46514611219578063a80fc071146111c8578063ad35efd414611169578063b256456914611119578063b88d4fde1461108f578063b8a3be661461105a578063b971302a1461100c578063bc2be1be14610fbd578063c156a11d14610bc9578063c87b56dd14610abe578063d4dbd20b14610a6d578063d511609f14610a22578063d975dfed146109d7578063e985e9c51461097e578063ea5ead19146106a9578063eac8f5b814610658578063f590c176146105fd578063f851a440146105d85763fdd46d601461026e575f80fd5b346105d45760603660031901126105d45760043561028a6133cc565b90604435916001600160801b038316908184036105d4576102a9613da2565b825f52600a60205260ff600160405f20015460a81c16156105c257825f52600a60205260ff600160405f20015460a01c166105af576001600160a01b03811690811561059c57821561058957835f5260036020526001600160a01b0360405f205416948583141580610579575b61055e576001600160801b0361032b866145fa565b16808511610544575061035090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a90613948565b6001600160801b036103ae81602084015116928260408183511692015116906135a3565b161115610512575b835f52600a6020526103da836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104fc575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916104c2575b50160361049757005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104e4915060203d6020116104ea575b6104dc818361352f565b810190613a8b565b5f61048e565b503d6104d2565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b50610583856144d5565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d4575f3660031901126105d45760206001600160a01b035f5416604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d45760403660031901126105d4576004356106c56133cc565b906106cf816145fa565b916106d8613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959576001600160a01b0381168015610946576001600160801b03841691821561058957835f5260036020526001600160a01b0360405f205416948583141580610936575b61055e576001600160801b03610764866145fa565b16808511610544575061078990855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107c390613948565b6001600160801b036107e781602084015116928260408183511692015116906135a3565b161115610904575b835f52600a602052610813836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806108ee575b61087957005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916108cf5750160361049757005b6108e8915060203d6020116104ea576104dc818361352f565b8461048e565b50835f52600960205260ff60405f205416610873565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107ef565b50610940856144d5565b1561074f565b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105d45760403660031901126105d4576109976133b6565b6001600160a01b036109a76133cc565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a116020916145fa565b6001600160801b0360405191168152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a6020526020600260405f20015460801c604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d45760203660031901126105d457600435610adb81613aab565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f1575f90610b4c575b610b4890604051918291602083526020830190613391565b0390f35b503d805f833e610b5c818361352f565b8101906020818303126105d45780519067ffffffffffffffff82116105d457019080601f830112156105d457815191610b9483613551565b91610ba2604051938461352f565b838352602084830101116105d457610b4892610bc49160208085019101613370565b610b30565b346105d45760403660031901126105d457600435610be56133cc565b90610bee613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f5260036020526001600160a01b0360405f20541691823303610fa657610c30826145fa565b6001600160801b03811680158015610cce575b5050506001600160a01b03811615610cbb57610c67826001600160a01b0392613c68565b169182610c815750637e27328960e01b5f5260045260245ffd5b808303610c8a57005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cd6613da2565b845f52600a60205260ff600160405f20015460a81c1615610f9457845f52600a60205260ff600160405f20015460a01c16610f81578515610f6e5761058957835f5260036020526001600160a01b0360405f205416918286141580610f5e575b610f43576001600160801b03610d4b866145fa565b16808311610f295750610d7090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610daa90613948565b6001600160801b03610dce81602084015116928260408183511692015116906135a3565b161115610ef7575b835f52600a6020526001600160a01b03600160405f20015416610dfa82878361477e565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610ee1575b610e65575b80610c43565b604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91610ec2575b5016036104975780610e5f565b610edb915060203d6020116104ea576104dc818361352f565b87610eb5565b50815f52600960205260ff60405f205416610e5a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610dd6565b828663287ecaef60e21b5f5260045260245260445260645ffd5b858563b34359d360e01b5f526004523360245260445260645ffd5b50610f68856144d5565b15610d36565b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d45760203660031901126105d4576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d45760803660031901126105d4576110a86133b6565b6110b06133cc565b6064359167ffffffffffffffff83116105d457366023840112156105d4578260040135916110dd83613551565b926110eb604051948561352f565b80845236602482870101116105d4576020815f926024611117980183880137850101526044359161399b565b005b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576111a190613bd4565b60405160058210156111b4576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d45760403660031901126105d4576112326133b6565b602435908115158092036105d4576001600160a01b03169081156112a157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4575f3660031901126105d4576040515f6002548060011c906001811680156113cb575b6020831081146113b7578285529081156113935750600114611335575b610b48836113218185038261352f565b604051918291602083526020830190613391565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061137957509091508101602001611321611311565b919260018160209254838588010152019101909291611361565b60ff191660208086019190915291151560051b840190910191506113219050611311565b634e487b7160e01b5f52602260045260245ffd5b91607f16916112f4565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c16156106475761145c90613bd4565b6005811015806111b45760028214908115611498575b8115611486575b6020826040519015158152f35b90506111b45760046020911482611479565b5050600381145f611472565b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d4578036036101206003198201126105d4576114df613da2565b60c482013590602219018112156105d45781019060048201359167ffffffffffffffff83116105d45760248101908360061b80360383136105d4576004602091611528876137ef565b96611536604051988961352f565b875282870193010101913683116105d457905b8282106117555750505081519161155f836137ef565b9261156d604051948561352f565b808452601f1961157c826137ef565b015f5b81811061173257505064ffffffffff4216916001600160801b036115a282613acc565b51511664ffffffffff8060206115b785613acc565b51015116850116604051916115cb836134da565b825260208201526115db86613acc565b526115e585613acc565b5060015b8281106116bd575050506115ff8260040161397a565b9261160c6024840161397a565b92611619604482016138a8565b916064820135936001600160a01b0385168095036105d4576020966116b596611675966001600160801b036116aa976001600160a01b0361165c60848a0161398e565b948161166a60a48c0161398e565b976040519d8e6134bd565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161383d565b610100820152613dfc565b604051908152f35b806001600160801b036116d260019385613ad9565b51511664ffffffffff8060206116eb5f1986018c613ad9565b510151168160206116fc8689613ad9565b5101511601166040519161170f836134da565b825260208201526117208289613ad9565b5261172b8188613ad9565b50016115e9565b602090604051611741816134da565b5f81525f838201528282890101520161157f565b60206040916117643685613807565b815201910190611549565b346105d45760203660031901126105d4576004356060610160604051611794816134f6565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201526040516117da81613513565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611a9a576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b03851687526118d7600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c161515885201613948565b6101208b019081526118e889613bd4565b60058110156111b457600214611a92575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119678c6134f6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b019889526119bb906138d4565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b4891613461565b5f87526118f9565b634e487b7160e01b5f52604160045260245ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d457611adf903690600401613430565b90611ae8613da2565b5f915b808310611af457005b611aff838284613884565b3592611b09613da2565b835f52600a60205260ff600160405f20015460a81c1615611e5357835f52600a60205260ff600160405f20015460a01c165f14611b535783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611e4157611b88815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57611b9681613aed565b90805f52600a602052611bae600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081611c029481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611de0575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d146001600160a01b03600160405f2001541694611cec88858861477e565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611d65575b50505050506001019190611aeb565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f91611dc2575b5016036104975780808080611d56565b611dda915060203d81116104ea576104dc818361352f565b87611db2565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611c4c565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600b602052610b48611eaa60405f206138d4565b604051918291602083526020830190613461565b346105d45760203660031901126105d457600435611eda613da2565b805f52600a60205260ff600160405f20015460a81c161561064757611efe81613bd4565b60058110156111b45760048103611f225750634a5541ef60e01b5f5260045260245ffd5b60038103611f3d575063fe19f19f60e01b5f5260045260245ffd5b600214611ff957611f62815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57805f52600a60205260ff60405f205460f01c1615611fe7576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d45760203660031901126105d4576004356001600160a01b0381168091036105d4576001600160a01b035f54163381036120e6575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120d25760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d4576121156133b6565b5f546001600160a01b0381163381036120e657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d45760203660031901126105d4576001600160a01b0361218b6133b6565b1680156121a8575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d45760203660031901126105d45760206121f2600435613aab565b6001600160a01b0360405191168152f35b346105d45760203660031901126105d45760043561221f6138bc565b50805f52600a60205260ff600160405f20015460a81c1615610647575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c16612269836134da565b8252602082015261228f8251809264ffffffffff60208092828151168552015116910152565bf35b346105d45760403660031901126105d45760043567ffffffffffffffff81116105d4576122c2903690600401613430565b9060243567ffffffffffffffff81116105d4576122e3903690600401613430565b9190926122ee613da2565b82810361261a575f5b81811061230057005b61230b818385613884565b35612317828486613884565b355f5260036020526001600160a01b0360405f2054169061234161233c84888a613884565b6138a8565b9161234a613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959578015612607576001600160801b0383169081156125f457825f5260036020526001600160a01b0360405f2054169384821415806125e4575b6125c9576001600160801b036123cc856145fa565b168084116125af57506123f190845f52600a602052600260405f20015460801c614620565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561242b90613948565b6001600160801b0361244f81602084015116928260408183511692015116906135a3565b16111561257d575b825f52600a6020526001600160a01b03600160405f2001541661247b83838361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612567575b6124ec575b505050506001016122f7565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91612549575b501603610497578080806124e0565b612561915060203d81116104ea576104dc818361352f565b8961253a565b50835f52600960205260ff60405f2054166124db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612457565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506125ee846144d5565b156123b7565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a11602091614547565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f6126bd82613bd4565b60058110156111b4576002036126db575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126ce565b346105d4575f3660031901126105d45760206001600160a01b0360085416604051908152f35b346105d45760203660031901126105d457600435612737613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c16156128b457612776816144d5565b15611e2b57805f5260036020526001600160a01b0360405f2054161515806128ad575b80612890575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612847575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061283557005b637e27328960e01b5f5260045260245ffd5b612866835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f1981540190556127ed565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561279f565b505f612799565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4576111176128f0366133f6565b906040519261290060208561352f565b5f845261399b565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d45760203660031901126105d457600435612974613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c165f146129bd57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611e41576129ef815f52600a6020526001600160a01b0360405f205416331490565b15611e2b576129fd81613aed565b90805f52600a602052612a15600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081612a699481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612beb575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b536001600160a01b03600160405f2001541694611cec88858861477e565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b9657005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f916108cf5750160361049757005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ab3565b346105d45760203660031901126105d457612c296133b6565b6001600160a01b035f541690338203612d6b57806001600160a01b03913b15612d3f57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f1575f91612d10575b5015612ce5576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d32915060203d602011612d38575b612d2a818361352f565b81019061386c565b82612c97565b503d612d20565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d45761014060031982360301126105d457612dbc613da2565b604051612dc8816134bd565b612dd4826004016133e2565b8152612de2602483016133e2565b6020820152612df36044830161356d565b604082015260648201356001600160a01b03811681036105d4576060820152612e1e608483016134b0565b6080820152612e2f60a483016134b0565b60a0820152612e4060c483016137dd565b60c082015260e482013567ffffffffffffffff81116105d457820191366023840112156105d457600483013592612e76846137ef565b90612e84604051928361352f565b848252602060048184019660061b83010101903682116105d457602401945b818610612ec55760206116b5866116aa878760e084015261010436910161383d565b6020604091612ed43689613807565b815201950194612ea3565b346105d45760203660031901126105d4576001600160a01b03612f006133b6565b165f526009602052602060ff60405f2054166040519015158152f35b346105d4575f3660031901126105d45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105d457611117612f67366133f6565b916135c3565b346105d4575f3660031901126105d4576020600754604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757612fc290613bd4565b60058110156111b4578060209115908115612fe3575b506040519015158152f35b600191501482612fd8565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576020905f90805f52600a835260ff60405f205460f01c1680613083575b613051575b506001600160801b0360405191168152f35b61307d9150805f52600a83526130776001600160801b03600260405f2001541691613aed565b906135a3565b8261303f565b50805f52600a835260ff600160405f20015460a01c161561303a565b346105d45760403660031901126105d4576130b86133b6565b6024356130c481613aab565b33151580613191575b8061315e575b6131325781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156130d3565b50336001600160a01b03821614156130cd565b346105d45760203660031901126105d45760206121f2600435613581565b346105d4575f3660031901126105d4576040515f6001548060011c90600181168015613273575b6020831081146113b757828552908115611393575060011461321557610b48836113218185038261352f565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061325957509091508101602001611321611311565b919260018160209254838588010152019101909291613241565b91607f16916131e9565b346105d4575f3660031901126105d457602060405167016345785d8a00008152f35b346105d45760203660031901126105d457600435906001600160e01b031982168092036105d457817f4906490600000000000000000000000000000000000000000000000000000000602093149081156132fb575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613346575b8115613335575b50836132f4565b6301ffc9a760e01b9150148361332e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613327565b5f5b8381106133815750505f910152565b8181015183820152602001613372565b906020916133aa81518092818552858086019101613370565b601f01601f1916010190565b600435906001600160a01b03821682036105d457565b602435906001600160a01b03821682036105d457565b35906001600160a01b03821682036105d457565b60609060031901126105d4576004356001600160a01b03811681036105d457906024356001600160a01b03811681036105d4579060443590565b9181601f840112156105d45782359167ffffffffffffffff83116105d4576020808501948460051b0101116105d457565b90602080835192838152019201905f5b81811061347e5750505090565b825180516001600160801b0316855260209081015164ffffffffff168186015260409094019390920191600101613471565b359081151582036105d457565b610120810190811067ffffffffffffffff821117611a9a57604052565b6040810190811067ffffffffffffffff821117611a9a57604052565b610180810190811067ffffffffffffffff821117611a9a57604052565b6060810190811067ffffffffffffffff821117611a9a57604052565b90601f8019910116810190811067ffffffffffffffff821117611a9a57604052565b67ffffffffffffffff8111611a9a57601f01601f191660200190565b35906001600160801b03821682036105d457565b61358a81613aab565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116120d257565b91906001600160a01b03168015610cbb57815f5260036020526001600160a01b0360405f2054161515806137d5575b806137b8575b6137a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836136f0575b6001600160a01b039350856136b9575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8a57505050565b6136d8825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613658565b919290508061374e575b1561370757828291613648565b828461371f57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b50338414801561377c575b806136fa5750825f526005602052336001600160a01b0360405f205416146136fa565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613759565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156135f8565b5060016135f2565b359064ffffffffff821682036105d457565b67ffffffffffffffff8111611a9a5760051b60200190565b91908260409103126105d45760405161381f816134da565b60206138388183956138308161356d565b8552016137dd565b910152565b91908260409103126105d457604051613855816134da565b6020808294613863816133e2565b84520135910152565b908160209103126105d4575180151581036105d45790565b91908110156138945760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105d45790565b604051906138c9826134da565b5f6020838281520152565b9081546138e0816137ef565b926138ee604051948561352f565b81845260208401905f5260205f205f915b83831061390c5750505050565b60016020819260405161391e816134da565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906138ff565b9060405161395581613513565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105d45790565b3580151581036105d45790565b906139a78382846135c3565b803b6139b4575b50505050565b6020916139fa6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613391565b03815f865af15f9181613a6a575b50613a365750613a166145cb565b80519081613a315782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613a5857505f8080806139ae565b633250574960e11b5f5260045260245ffd5b613a8491925060203d6020116104ea576104dc818361352f565b905f613a08565b908160209103126105d457516001600160e01b0319811681036105d45790565b805f5260036020526001600160a01b0360405f205416908115612835575090565b8051156138945760200190565b80518210156138945760209160051b010190565b9064ffffffffff421691805f52600b602052613b0b60405f206138d4565b908364ffffffffff6020613b1e85613acc565b5101511611613bcd57805f52600a6020528364ffffffffff60405f205460c81c161115613bae57506001600160801b03613b5782613acc565b515116916001925b8251841015613ba7578464ffffffffff6020613b7b8787613ad9565b5101511611613ba7576001600160801b0360019181613b9a8787613ad9565b5151160116930192613b5f565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613bf65750600490565b805f52600a60205260405f205460f81c613c6257805f52600a60205264ffffffffff60405f205460a01c164210613c5d57613c3081613aed565b905f52600a6020526001600160801b0380600260405f200154169116105f14613c5857600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613d90575b80613d73575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613d3c575b1680613d24575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613ce0565b613d5b835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613cd9565b50805f52600a60205260ff600160405f20015460b01c1615613c8d565b506001600160a01b0382161515613c87565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dd457565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613e1e6001600160801b036040840151166020610100850151015190614640565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156144ad578015614485578151801561445d577f00000000000000000000000000000000000000000000000000000000000000008111614432575064ffffffffff6020613e8c84613acc565b510151168110156143ee57505f905f905f81515f905b808210614366575050505064ffffffffff804216911690818110156143385750506001600160801b03169081810361430a57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406e8751975f19890190613ad9565b51015160c81b169360a01b169116171785555f5b818110614258575050600187016007556001600160a01b036020830151168015610cbb576140b8886001600160a01b0392613c68565b1661422c5786826141066001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061471d565b6001600160801b03602084015116806141fc575b506001600160a01b03815116946141f16141d36001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141788b6134da565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190613461565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614226906001600160a01b036060840151166001600160a01b03610100850151511690339061471d565b5f61411a565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142738160e0870151613ad9565b5182549268010000000000000000841015611a9a5760018401808255841015613894576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614082565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919350919361438a906001600160801b036143818588613ad9565b51511690614620565b9364ffffffffff80602061439e8685613ad9565b510151169416808511156143ba57506001849301909291613ea2565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff60206143ff84613acc565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561451b575b508115614502575090565b90506001600160a01b036145163392613581565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6144f7565b805f52600a60205261455e600260405f2001613948565b90805f52600a60205260ff600160405f20015460a01c165f1461458c5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6145ae57506145ab90613aed565b90565b6145ab91506001600160801b0360408183511692015116906135a3565b3d156145f5573d906145dc82613551565b916145ea604051938461352f565b82523d5f602084013e565b606090565b6145ab9061460781614547565b905f52600a602052600260405f20015460801c906135a3565b906001600160801b03809116911601906001600160801b0382116120d257565b91909160405161464f816134da565b5f81525f6020820152926001600160801b0382169081156147005767016345785d8a000081116146c95761468b6001600160801b039183614853565b16602085019181835211156146b5576001600160801b0391826146b0925116906135a3565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614711816134da565b5f81525f602082015290565b9091926001600160a01b0361477c9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261477760848361352f565b6147ce565b565b61477c926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261477760648361352f565b5f806001600160a01b036147f793169360208151910182865af16147f06145cb565b9083614901565b8051908115159182614838575b505061480d5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61484b925060208091830101910161386c565b155f80614804565b9091905f19838209838202918280831092039180830392146148f057670de0b6b3a76400008210156148c0577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061493e575080511561491657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614984575b61494f575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561494756fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol index 2b8724d0a..d8380cc93 100644 --- a/src/SablierV2LockupLinear.sol +++ b/src/SablierV2LockupLinear.sol @@ -192,7 +192,7 @@ contract SablierV2LockupLinear is uint256 blockTimestamp = block.timestamp; // If the cliff time or the start time is in the future, return zero. - if (cliffTime > blockTimestamp || startTime > blockTimestamp) { + if (cliffTime > blockTimestamp || startTime >= blockTimestamp) { return 0; } From 4fada2ab16e669da9eba4976815363845ab6bc0a Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Sat, 29 Jun 2024 23:02:26 +0100 Subject: [PATCH 126/132] chore: explicitely set gas_limit in foundry config --- foundry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/foundry.toml b/foundry.toml index 89749dd4f..a95fb8642 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,6 +7,7 @@ { access = "read", path = "package.json" }, { access = "read-write", path = "./benchmark/results" }, ] + gas_limit = 9223372036854775807 gas_reports = [ "SablierV2LockupDynamic", "SablierV2LockupLinear", From 9eaac3403cad8a5a8f5f4f8a35daeccf3519a160 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 1 Jul 2024 13:39:58 +0100 Subject: [PATCH 127/132] implementing suggestions from Egis audit review (#960) * refactor: index admin in AllowToHook event * feat: include dash in alphanumeric check * build: update precompiles * docs: update natspec * refactor: rename isAlphanumericWithSpaces to IsAllowedCharacter * test: fixes --------- Co-authored-by: Paul Razvan Berg --- precompiles/Precompiles.sol | 8 +- src/SablierV2NFTDescriptor.sol | 15 +-- src/interfaces/ISablierV2Lockup.sol | 2 +- .../IsAllowedCharacter.t.sol | 104 ++++++++++++++++++ .../IsAllowedCharacter.tree} | 2 +- .../isAlphanumericWithSpaces.t.sol | 100 ----------------- ...hSpaces.t.sol => isAllowedCharacter.t.sol} | 12 +- test/mocks/NFTDescriptorMock.sol | 4 +- test/utils/Events.sol | 2 +- 9 files changed, 128 insertions(+), 121 deletions(-) create mode 100644 test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol rename test/integration/concrete/nft-descriptor/{is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree => is-allowed-character/IsAllowedCharacter.tree} (91%) delete mode 100644 test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol rename test/integration/fuzz/nft-descriptor/{isAlphanumericWithSpaces.t.sol => isAllowedCharacter.t.sol} (74%) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index f4baef6f7..a63fc535f 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,13 +26,13 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e457615a426060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615634908161040e823960805181613927015260a051818181610bbf01526139f10152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127be57508063027b67441461279c57806306fdde03146126e1578063081812fc146126c3578063095ea7b3146125be5780631400ecec1461250d5780631c1cdd4c146124a95780631e99d5691461248c57806323b872dd14612475578063303acc851461243857806331df3d4814612325578063406887cb146121b357806340e58ee514611e9a578063425d30dd14611e4a57806342842e0e14611e2157806342966c6814611c5d5780634426757014611c375780634857501f14611bc65780634869e12d14611b8c5780634cc55e1114611a9457806354c02292146117e357806357404b12146117555780636352211e146117265780636d0cee751461172657806370a08231146116bc57806375829def1461164e5780637cad6cd11461155d5780637de6b1db146113de5780638659c27014610fe0578063894e9a0d14610cb15780638f69b99314610c315780639067b67714610be25780639188ec8414610ba857806395d89b4114610aa0578063a22cb465146109ec578063a80fc0711461099b578063ad35efd41461093c578063b2564569146108ec578063b637b86514610893578063b88d4fde1461080b578063b8a3be66146107d6578063b971302a14610788578063bc2be1be14610739578063c156a11d14610609578063c87b56dd146104f3578063d4dbd20b146104a2578063d511609f14610457578063d975dfed1461040c578063e985e9c5146103b3578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128eb565b6044356001600160801b03811681036102b0576102ae916102a661391d565b6004356133d1565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b0576102ae6004356103a46128eb565b6103ad826141f8565b91613062565b346102b05760403660031901126102b0576103cc6128d5565b6001600160a01b036103dc6128eb565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576104466020916141f8565b6001600160801b0360405191168152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b0576004356105108161369f565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156105fe575f90610581575b61057d906040519182916020835260208301906128b0565b0390f35b503d805f833e6105918183612a6e565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105c983612a90565b916105d76040519384612a6e565b838352602084830101116102b05761057d926105f9916020808501910161288f565b610565565b6040513d5f823e3d90fd5b346102b05760403660031901126102b0576004356106256128eb565b9061062e61391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f5260036020526001600160a01b0360405f2054169182330361071957610670826141f8565b6001600160801b038116610708575b506001600160a01b038116156106f5576106a1826001600160a01b03926137e3565b1691826106bb5750637e27328960e01b5f5260045260245ffd5b8083036106c457005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610713908484613062565b8361067f565b5063216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108246128d5565b61082c6128eb565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161085983612a90565b926108676040519485612a6e565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b60205261057d6108d860405f20612eeb565b604051918291602083526020830190612980565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576109749061374f565b6040516005821015610987576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a056128d5565b602435908115158092036102b0576001600160a01b0316908115610a7457335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610b9e575b602083108114610b8a57828552908115610b665750600114610b08575b61057d83610af481850382612a6e565b6040519182916020835260208301906128b0565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b4c57509091508101602001610af4610ae4565b919260018160209254838588010152019101909291610b34565b60ff191660208086019190915291151560051b84019091019150610af49050610ae4565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ac7565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c699061374f565b6005811015806109875760028214908115610ca5575b8115610c93575b6020826040519015158152f35b90506109875760046020911482610c86565b5050600381145f610c7f565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fcc57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d2c612e9b565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d6781612a51565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e06600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612eb9565b61012083019081526002610e198c61374f565b610e22816129f2565b14610fc4575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610e996101808d612a6e565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610eed90612eeb565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057d91612980565b5f8752610e28565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101190369060040161294f565b9061101a61391d565b5f915b80831061102657005b611031838284612e2a565b359261103b61391d565b835f52600a60205260ff600160405f20015460a81c16156113cb57835f52600a60205260ff600160405f20015460a01c165f146110855783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113b9576110ba815f52600a6020526001600160a01b0360405f205416331490565b156113a3576110c8816136c0565b90805f52600a6020526110e0600260405f2001612eb9565b916001600160801b038351166001600160801b038216101561138f57815f52600a60205260ff60405f205460f01c161561137b57806001600160801b03602081611134948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611356575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061124f6001600160a01b03600160405f2001541694611227888588614652565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff611299866001600160a01b03165f52600960205260405f2090565b54166112af575b5050505050600101919061101d565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91611328575b50160361130c57808080806112a0565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611349915060203d811161134f575b6113418183612a6e565b81019061367f565b876112fc565b503d611337565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561117e565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b0576004356113fa61391d565b805f52600a60205260ff600160405f20015460a81c16156103235761141e8161374f565b611427816129f2565b600481036114425750634a5541ef60e01b5f5260045260245ffd5b61144b816129f2565b60038103611466575063fe19f19f60e01b5f5260045260245ffd5b600290611472816129f2565b1461154b57611495815f52600a6020526001600160a01b0360405f205416331490565b1561152c57805f52600a60205260ff60405f205460f01c161561151a576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611638575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116245760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116676128d5565b5f546001600160a01b03811633810361163857506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116dd6128d5565b1680156116fa575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174460043561369f565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b057600435611771612e83565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117bb83612a35565b825260208201526117e18251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761181e61391d565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b057611860913691612d46565b9081519161186d83612d2e565b9261187b6040519485612a6e565b808452601f1961188a82612d2e565b015f5b818110611a7d57505064ffffffffff4216916001600160801b036118b082613977565b51511667ffffffffffffffff60206118c784613977565b5101511664ffffffffff8060406118dd86613977565b5101511686011690604051926118f284612a19565b83526020830152604082015261190786613977565b5261191185613977565b5060015b8281106119e95750505061192b82600401612e62565b9261193860248401612e62565b9261194560448201612e4e565b916064820135936001600160a01b0385168095036102b0576020966119e1966119a1966001600160801b036119d6976001600160a01b0361198860848a01612e76565b948161199660a48c01612e76565b976040519d8e6129fc565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612de3565b610100820152613998565b604051908152f35b806001600160801b036119fe60019385613984565b51511667ffffffffffffffff6020611a168487613984565b5101511664ffffffffff806040611a305f1987018d613984565b51015116816040611a41878a613984565b5101511601169060405192611a5584612a19565b835260208301526040820152611a6b8289613984565b52611a768188613984565b5001611915565b602090611a88612e9b565b8282890101520161188d565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ac590369060040161294f565b9060243567ffffffffffffffff81116102b057611ae690369060040161294f565b9091611af061391d565b818403611b5c575f5b848110611b0257005b80611b56611b136001938886612e2a565b35611b1f838987612e2a565b355f5260036020526001600160a01b0360405f205416611b48611b4385898b612e2a565b612e4e565b91611b5161391d565b6133d1565b01611af9565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610446602091614148565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611bff8261374f565b600581101561098757600203611c1d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c10565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c7961391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611df657611cb8816140d6565b156113a357805f5260036020526001600160a01b0360405f205416151580611def575b80611dd2575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d89575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d7757005b637e27328960e01b5f5260045260245ffd5b611da8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d2f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611ce1565b505f611cdb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3236612915565b9060405192611e42602085612a6e565b5f8452612f72565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611eb661391d565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611eff57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113b957611f31815f52600a6020526001600160a01b0360405f205416331490565b1561152c57611f3f816136c0565b90805f52600a602052611f57600260405f2001612eb9565b916001600160801b038351166001600160801b03821610156121a057815f52600a60205260ff60405f205460f01c161561218d57806001600160801b03602081611fab948188511603169501511690612ae2565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612168575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061209e6001600160a01b03600160405f2001541694611227888588614652565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120e157005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91612149575b50160361213757005b632187e5e760e21b5f5260045260245ffd5b612162915060203d60201161134f576113418183612a6e565b8461212e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611ff5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121cc6128d5565b6001600160a01b035f54169033820361230e57806001600160a01b03913b156122e257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156105fe575f916122b3575b5015612288576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122d5915060203d6020116122db575b6122cd8183612a6e565b810190612e12565b8261223a565b503d6122c3565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761235f61391d565b6040519061236c826129fc565b61237881600401612901565b825261238660248201612901565b602083015261239760448201612aac565b604083015260648101356001600160a01b03811681036102b05760608301526123c2608482016129e5565b60808301526123d360a482016129e5565b60a08301526123e460c48201612d1c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119d66119e1926124286020953690602460048201359101612d46565b60e0840152610104369101612de3565b346102b05760203660031901126102b0576001600160a01b036124596128d5565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248636612915565b91612b02565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e19061374f565b6005811015610987578060209115908115612502575b506040519015158152f35b6001915014826124f7565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125a2575b612570575b506001600160801b0360405191168152f35b61259c9150805f52600a83526125966001600160801b03600260405f20015416916136c0565b90612ae2565b8261255e565b50805f52600a835260ff600160405f20015460a01c1615612559565b346102b05760403660031901126102b0576125d76128d5565b6024356125e38161369f565b331515806126b0575b8061267d575b6126515781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125f2565b50336001600160a01b03821614156125ec565b346102b05760203660031901126102b0576020611744600435612ac0565b346102b0575f3660031901126102b0576040515f6001548060011c90600181168015612792575b602083108114610b8a57828552908115610b6657506001146127345761057d83610af481850382612a6e565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061277857509091508101602001610af4610ae4565b919260018160209254838588010152019101909291612760565b91607f1691612708565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f49064906000000000000000000000000000000000000000000000000000000006020931490811561281a575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612865575b8115612854575b5083612813565b6301ffc9a760e01b9150148361284d565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612846565b5f5b8381106128a05750505f910152565b8181015183820152602001612891565b906020916128c98151809281855285808601910161288f565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b81811061299d5750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612990565b359081151582036102b057565b6005111561098757565b610120810190811067ffffffffffffffff821117610fcc57604052565b6060810190811067ffffffffffffffff821117610fcc57604052565b6040810190811067ffffffffffffffff821117610fcc57604052565b610140810190811067ffffffffffffffff821117610fcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610fcc57604052565b67ffffffffffffffff8111610fcc57601f01601f191660200190565b35906001600160801b03821682036102b057565b612ac98161369f565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162457565b91906001600160a01b031680156106f557815f5260036020526001600160a01b0360405f205416151580612d14575b80612cf7575b612ce4577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2f575b6001600160a01b03935085612bf8575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036106c457505050565b612c17825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b97565b9192905080612c8d575b15612c4657828291612b87565b8284612c5e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cbb575b80612c395750825f526005602052336001600160a01b0360405f20541614612c39565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c98565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b37565b506001612b31565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fcc5760051b60200190565b929192612d5282612d2e565b93612d606040519586612a6e565b60606020868581520193028201918183116102b057925b828410612d845750505050565b6060848303126102b05760405190612d9b82612a19565b612da485612aac565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612dd360408801612d1c565b6040820152815201930192612d77565b91908260409103126102b057604051612dfb81612a35565b6020808294612e0981612901565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e3a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612e9082612a35565b5f6020838281520152565b60405190612ea882612a19565b5f6040838281528260208201520152565b90604051612ec681612a19565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612ef781612d2e565b92612f056040519485612a6e565b81845260208401905f5260205f205f915b838310612f235750505050565b600160208192604051612f3581612a19565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f16565b90612f7e838284612b02565b803b612f8b575b50505050565b602091612fd16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b0565b03815f865af15f9181613041575b5061300d5750612fed6141c9565b805190816130085782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361302f57505f808080612f85565b633250574960e11b5f5260045260245ffd5b61305b91925060203d60201161134f576113418183612a6e565b905f612fdf565b9061306b61391d565b815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f205416948583141580613344575b613310576001600160801b036130f7866141f8565b168085116132dd575061311c90855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561315f90612eb9565b6001600160801b036131838160208401511692826040818351169201511690612ae2565b1611156132ab575b835f52600a6020526131af836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613295575b6132195750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f91613276575b50160361213757808080612f85565b61328f915060203d60201161134f576113418183612a6e565b5f613267565b50835f52600960205260ff60405f20541661320f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561318b565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061334e856140d6565b156130e2565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c16156133bf57815f52600a60205260ff600160405f20015460a01c166133ac576001600160a01b0381168015613380576001600160801b03841691821561335457835f5260036020526001600160a01b0360405f20541694858314158061366f575b613310576001600160801b0361345e866141f8565b168085116132dd575061348390855f52600a602052600260405f20015460801c61421e565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134c690612eb9565b6001600160801b036134ea8160208401511692826040818351169201511690612ae2565b16111561363d575b835f52600a602052613516836001600160a01b03600160405f200154169283614652565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613618575b6135805750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f916135f9575b5016036135dd57808080612f85565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613612915060203d60201161134f576113418183612a6e565b5f6135ce565b5060ff613636856001600160a01b03165f52600960205260405f2090565b5416613576565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556134f2565b50613679856140d6565b15613449565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d77575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561374957815f52600a60205264ffffffffff60405f205460c81c16111561372e57805f52600b602052600160405f2054115f1461372557613722906142fe565b90565b6137229061423e565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137715750600490565b805f52600a60205260405f205460f81c6137dd57805f52600a60205264ffffffffff60405f205460a01c1642106137d8576137ab816136c0565b905f52600a6020526001600160801b0380600260405f200154169116105f146137d357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061390b575b806138ee575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138b7575b168061389f575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561385b565b6138d6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613854565b50805f52600a60205260ff600160405f20015460b01c1615613808565b506001600160a01b0382161515613802565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361394f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e3a5760200190565b8051821015612e3a5760209160051b010190565b906139ba6001600160801b036040840151166020610100850151015190614514565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140ae578015614086578151801561405e577f00000000000000000000000000000000000000000000000000000000000000008111614033575064ffffffffff6040613a2884613977565b51015116811015613fef57505f905f905f81515f905b808210613f67575050505064ffffffffff80421691169081811015613f395750506001600160801b031690818103613f0b57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c138751975f19890190613984565b51015160c81b169360a01b169116171785555f5b818110613dfd575050600187016007556001600160a01b0360208301511680156106f557613c5d886001600160a01b03926137e3565b16613dd1578682613cab6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145f1565b6001600160801b0360208401511680613da1575b506001600160a01b0381511694613d96613d786001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d1d8b612a35565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612980565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dcb906001600160a01b036060840151166001600160a01b0361010085015151169033906145f1565b5f613cbf565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e188160e0870151613984565b51825468010000000000000000811015610fcc5760018101808555811015612e3a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c27565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f8b906001600160801b03613f828588613984565b5151169061421e565b9364ffffffffff806040613f9f8685613984565b51015116941680851115613fbb57506001849301909291613a3e565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400084613977565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561411c575b508115614103575090565b90506001600160a01b036141173392612ac0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f8565b805f52600a60205261415f600260405f2001612eb9565b90805f52600a60205260ff600160405f20015460a01c165f1461418d5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ac5750613722906136c0565b61372291506001600160801b036040818351169201511690612ae2565b3d156141f3573d906141da82612a90565b916141e86040519384612a6e565b82523d5f602084013e565b606090565b6137229061420581614148565b905f52600a602052600260405f20015460801c90612ae2565b906001600160801b03809116911601906001600160801b03821161162457565b5f818152600a60205260409020546142759064ffffffffff60a082901c811660c89290921c811682900381169142821603166146a2565b90805f52600b60205260405f20805415612e3a575f526142ca67ffffffffffffffff60205f205460801c1692825f52600a6020526142c56001600160801b03600260405f20015416948592614782565b6147f5565b9182136142e757506142e36001600160801b03916148d0565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061432282612a51565b6101206143b560028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eb9565b92019182525f52600b6020526143cd60405f20612eeb565b915f9264ffffffffff60406143e183613977565b510151168664ffffffffff5f925b16106144d5578161446664ffffffffff9697988784816001600160801b0361441e6142c59861446b9b9a613984565b5151169a8b9867ffffffffffffffff6020614439868b613984565b510151169782604061444b8784613984565b5101511694806144b8575050511680925b03169203166146a2565b614782565b91821361448c5750906001600160801b0361448681936148d0565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b3575090565b905090565b60409250906144ca915f190190613984565b51015116809261445c565b936001600160801b03600191816144ec8886613984565b51511601169401958064ffffffffff8060406145088b87613984565b510151169892986143ef565b91909160405161452381612a35565b5f81525f6020820152926001600160801b0382169081156145d45767016345785d8a0000811161459d5761455f6001600160801b0391836154ed565b1660208501918183521115614589576001600160801b03918261458492511690612ae2565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e581612a35565b5f81525f602082015290565b9091926001600160a01b036146509481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261464b608483612a6e565b614905565b565b614650926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261464b606483612a6e565b600160ff1b81148015614775575b61474d575f811215614744576146d4815f035b5f84121561473d57835f039061498a565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470e575f19911813156147095790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061498a565b6146d4816146c3565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146b0565b8061479c575061479857670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e757806147bf575050670de0b6b3a764000090565b670de0b6b3a764000081146147e3576147de906142c561372293614a90565b614be7565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c3575b61489b575f81121561489257614827815f035b5f84121561488b57835f03906154ed565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161485c575f19911813156147095790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ed565b61482781614816565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614803565b5f81126148da5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492e93169360208151910182865af16149276141c9565b908361559b565b805190811515918261496f575b50506149445750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149829250602080918301019101612e12565b155f8061493b565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a555781841015614a1b57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a62570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a62576ec097ce7bc90715b34b9f10000000000590565b805f811315614bbc57670de0b6b3a76400008112614b9c57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8957506706f05b59d3b20000905b5f8213614b535750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b7b575b60011d90614b46565b809192019160011d90614b72565b9050670de0b6b3a7640000929150020290565b5f1991508015614a62576ec097ce7bc90715b34b9f100000000005614aad565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c145768033dd1780914b971141981126137d857614c0b905f03614be7565b61372290614a76565b680a688906bd8affffff81136154c257670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538d575b670de0b6b3a76400009066ff000000000000831661527d575b65ff00000000008316615175575b64ff000000008316615075575b63ff0000008316614f7d575b62ff00008316614e8d575b61ff008316614da5575b60ff8316614cc5575b029060401c60bf031c90565b60808316614d92575b60408316614d7f575b60208316614d6c575b60108316614d59575b60088316614d46575b60048316614d33575b60028316614d20575b6001831615614cb957680100000000000000010260401c614cb9565b680100000000000000010260401c614d04565b680100000000000000030260401c614cfb565b680100000000000000060260401c614cf2565b6801000000000000000b0260401c614ce9565b680100000000000000160260401c614ce0565b6801000000000000002c0260401c614cd7565b680100000000000000590260401c614cce565b6180008316614e7a575b6140008316614e67575b6120008316614e54575b6110008316614e41575b6108008316614e2e575b6104008316614e1b575b6102008316614e08575b610100831615614cb057680100000000000000b10260401c614cb0565b680100000000000001630260401c614deb565b680100000000000002c60260401c614de1565b6801000000000000058c0260401c614dd7565b68010000000000000b170260401c614dcd565b6801000000000000162e0260401c614dc3565b68010000000000002c5d0260401c614db9565b680100000000000058b90260401c614daf565b628000008316614f6a575b624000008316614f57575b622000008316614f44575b621000008316614f31575b620800008316614f1e575b620400008316614f0b575b620200008316614ef8575b62010000831615614ca6576801000000000000b1720260401c614ca6565b680100000000000162e40260401c614eda565b6801000000000002c5c80260401c614ecf565b68010000000000058b910260401c614ec4565b680100000000000b17210260401c614eb9565b68010000000000162e430260401c614eae565b680100000000002c5c860260401c614ea3565b6801000000000058b90c0260401c614e98565b63800000008316615062575b6340000000831661504f575b6320000000831661503c575b63100000008316615029575b63080000008316615016575b63040000008316615003575b63020000008316614ff0575b6301000000831615614c9b5768010000000000b172180260401c614c9b565b6801000000000162e4300260401c614fd1565b68010000000002c5c8600260401c614fc5565b680100000000058b90c00260401c614fb9565b6801000000000b17217f0260401c614fad565b680100000000162e42ff0260401c614fa1565b6801000000002c5c85fe0260401c614f95565b68010000000058b90bfc0260401c614f89565b6480000000008316615162575b644000000000831661514f575b642000000000831661513c575b6410000000008316615129575b6408000000008316615116575b6404000000008316615103575b64020000000083166150f0575b640100000000831615614c8f57680100000000b17217f80260401c614c8f565b68010000000162e42ff10260401c6150d0565b680100000002c5c85fe30260401c6150c3565b6801000000058b90bfce0260401c6150b6565b68010000000b17217fbb0260401c6150a9565b6801000000162e42fff00260401c61509c565b68010000002c5c8601cc0260401c61508f565b680100000058b90c0b490260401c615082565b65800000000000831661526a575b654000000000008316615257575b652000000000008316615244575b651000000000008316615231575b65080000000000831661521e575b65040000000000831661520b575b6502000000000083166151f8575b65010000000000831615614c82576801000000b1721835510260401c614c82565b680100000162e430e5a20260401c6151d7565b6801000002c5c863b73f0260401c6151c9565b68010000058b90cf1e6e0260401c6151bb565b680100000b1721bcfc9a0260401c6151ad565b68010000162e43f4f8310260401c61519f565b680100002c5c89d5ec6d0260401c615191565b6801000058b91b5bc9ae0260401c615183565b6680000000000000831661537a575b66400000000000008316615367575b66200000000000008316615354575b66100000000000008316615341575b6608000000000000831661532e575b6604000000000000831661531b575b66020000000000008316615308575b6601000000000000831615614c745768010000b17255775c040260401c614c74565b6801000162e525ee05470260401c6152e6565b68010002c5cc37da94920260401c6152d7565b680100058ba01fb9f96d0260401c6152c8565b6801000b175effdc76ba0260401c6152b9565b680100162f3904051fa10260401c6152aa565b6801002c605e2e8cec500260401c61529b565b68010058c86da1c09ea20260401c61528c565b67800000000000000082166154a3575b670de0b6b3a7640000906740000000000000008316615490575b672000000000000000831661547d575b671000000000000000831661546a575b6708000000000000008316615457575b6704000000000000008316615444575b6702000000000000008316615431575b670100000000000000831661541e575b9050614c5b565b680100b1afa5abcbed610260401c615417565b68010163da9fb33356d80260401c615407565b680102c9a3e778060ee70260401c6153f7565b6801059b0d31585743ae0260401c6153e7565b68010b5586cf9890f62a0260401c6153d7565b6801172b83c7d517adce0260401c6153c7565b6801306fe0a31b7152df0260401c6153b7565b5077b504f333f9de64848000000000000000000000000000000061539d565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558a57670de0b6b3a764000082101561555a577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d857508051156155b057805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561e575b6155e9575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155e156fea164736f6c634300081a000a"; + hex"60c0604052346103e457615a3f6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615631908161040e823960805181613924015260a051818181610bbf01526139ee0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127bb57508063027b67441461279957806306fdde03146126de578063081812fc146126c0578063095ea7b3146125bb5780631400ecec1461250a5780631c1cdd4c146124a65780631e99d5691461248957806323b872dd14612472578063303acc851461243557806331df3d4814612322578063406887cb146121b357806340e58ee514611e9a578063425d30dd14611e4a57806342842e0e14611e2157806342966c6814611c5d5780634426757014611c375780634857501f14611bc65780634869e12d14611b8c5780634cc55e1114611a9457806354c02292146117e357806357404b12146117555780636352211e146117265780636d0cee751461172657806370a08231146116bc57806375829def1461164e5780637cad6cd11461155d5780637de6b1db146113de5780638659c27014610fe0578063894e9a0d14610cb15780638f69b99314610c315780639067b67714610be25780639188ec8414610ba857806395d89b4114610aa0578063a22cb465146109ec578063a80fc0711461099b578063ad35efd41461093c578063b2564569146108ec578063b637b86514610893578063b88d4fde1461080b578063b8a3be66146107d6578063b971302a14610788578063bc2be1be14610739578063c156a11d14610609578063c87b56dd146104f3578063d4dbd20b146104a2578063d511609f14610457578063d975dfed1461040c578063e985e9c5146103b3578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128e8565b6044356001600160801b03811681036102b0576102ae916102a661391a565b6004356133ce565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b0576102ae6004356103a46128e8565b6103ad826141f5565b9161305f565b346102b05760403660031901126102b0576103cc6128d2565b6001600160a01b036103dc6128e8565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576104466020916141f5565b6001600160801b0360405191168152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b0576004356105108161369c565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156105fe575f90610581575b61057d906040519182916020835260208301906128ad565b0390f35b503d805f833e6105918183612a6b565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105c983612a8d565b916105d76040519384612a6b565b838352602084830101116102b05761057d926105f9916020808501910161288c565b610565565b6040513d5f823e3d90fd5b346102b05760403660031901126102b0576004356106256128e8565b9061062e61391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f5260036020526001600160a01b0360405f2054169182330361071957610670826141f5565b6001600160801b038116610708575b506001600160a01b038116156106f5576106a1826001600160a01b03926137e0565b1691826106bb5750637e27328960e01b5f5260045260245ffd5b8083036106c457005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61071390848461305f565b8361067f565b5063216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108246128d2565b61082c6128e8565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161085983612a8d565b926108676040519485612a6b565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f6f565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b60205261057d6108d860405f20612ee8565b60405191829160208352602083019061297d565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576109749061374c565b6040516005821015610987576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a056128d2565b602435908115158092036102b0576001600160a01b0316908115610a7457335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610b9e575b602083108114610b8a57828552908115610b665750600114610b08575b61057d83610af481850382612a6b565b6040519182916020835260208301906128ad565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b4c57509091508101602001610af4610ae4565b919260018160209254838588010152019101909291610b34565b60ff191660208086019190915291151560051b84019091019150610af49050610ae4565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ac7565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c699061374c565b6005811015806109875760028214908115610ca5575b8115610c93575b6020826040519015158152f35b90506109875760046020911482610c86565b5050600381145f610c7f565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fcc57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d2c612e98565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d6781612a4e565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e06600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612eb6565b61012083019081526002610e198c61374c565b610e22816129ef565b14610fc4575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610e996101808d612a6b565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610eed90612ee8565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057d9161297d565b5f8752610e28565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101190369060040161294c565b9061101a61391a565b5f915b80831061102657005b611031838284612e27565b359261103b61391a565b835f52600a60205260ff600160405f20015460a81c16156113cb57835f52600a60205260ff600160405f20015460a01c165f146110855783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113b9576110ba815f52600a6020526001600160a01b0360405f205416331490565b156113a3576110c8816136bd565b90805f52600a6020526110e0600260405f2001612eb6565b916001600160801b038351166001600160801b038216101561138f57815f52600a60205260ff60405f205460f01c161561137b57806001600160801b03602081611134948188511603169501511690612adf565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611356575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061124f6001600160a01b03600160405f200154169461122788858861464f565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff611299866001600160a01b03165f52600960205260405f2090565b54166112af575b5050505050600101919061101d565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91611328575b50160361130c57808080806112a0565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611349915060203d811161134f575b6113418183612a6b565b81019061367c565b876112fc565b503d611337565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561117e565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b0576004356113fa61391a565b805f52600a60205260ff600160405f20015460a81c16156103235761141e8161374c565b611427816129ef565b600481036114425750634a5541ef60e01b5f5260045260245ffd5b61144b816129ef565b60038103611466575063fe19f19f60e01b5f5260045260245ffd5b600290611472816129ef565b1461154b57611495815f52600a6020526001600160a01b0360405f205416331490565b1561152c57805f52600a60205260ff60405f205460f01c161561151a576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611638575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116245760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116676128d2565b5f546001600160a01b03811633810361163857506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116dd6128d2565b1680156116fa575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174460043561369c565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b057600435611771612e80565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117bb83612a32565b825260208201526117e18251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761181e61391a565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b057611860913691612d43565b9081519161186d83612d2b565b9261187b6040519485612a6b565b808452601f1961188a82612d2b565b015f5b818110611a7d57505064ffffffffff4216916001600160801b036118b082613974565b51511667ffffffffffffffff60206118c784613974565b5101511664ffffffffff8060406118dd86613974565b5101511686011690604051926118f284612a16565b83526020830152604082015261190786613974565b5261191185613974565b5060015b8281106119e95750505061192b82600401612e5f565b9261193860248401612e5f565b9261194560448201612e4b565b916064820135936001600160a01b0385168095036102b0576020966119e1966119a1966001600160801b036119d6976001600160a01b0361198860848a01612e73565b948161199660a48c01612e73565b976040519d8e6129f9565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612de0565b610100820152613995565b604051908152f35b806001600160801b036119fe60019385613981565b51511667ffffffffffffffff6020611a168487613981565b5101511664ffffffffff806040611a305f1987018d613981565b51015116816040611a41878a613981565b5101511601169060405192611a5584612a16565b835260208301526040820152611a6b8289613981565b52611a768188613981565b5001611915565b602090611a88612e98565b8282890101520161188d565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ac590369060040161294c565b9060243567ffffffffffffffff81116102b057611ae690369060040161294c565b9091611af061391a565b818403611b5c575f5b848110611b0257005b80611b56611b136001938886612e27565b35611b1f838987612e27565b355f5260036020526001600160a01b0360405f205416611b48611b4385898b612e27565b612e4b565b91611b5161391a565b6133ce565b01611af9565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610446602091614145565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611bff8261374c565b600581101561098757600203611c1d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c10565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c7961391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611df657611cb8816140d3565b156113a357805f5260036020526001600160a01b0360405f205416151580611def575b80611dd2575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d89575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d7757005b637e27328960e01b5f5260045260245ffd5b611da8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d2f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611ce1565b505f611cdb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3236612912565b9060405192611e42602085612a6b565b5f8452612f6f565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611eb661391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611eff57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113b957611f31815f52600a6020526001600160a01b0360405f205416331490565b1561152c57611f3f816136bd565b90805f52600a602052611f57600260405f2001612eb6565b916001600160801b038351166001600160801b03821610156121a057815f52600a60205260ff60405f205460f01c161561218d57806001600160801b03602081611fab948188511603169501511690612adf565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612168575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061209e6001600160a01b03600160405f200154169461122788858861464f565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120e157005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91612149575b50160361213757005b632187e5e760e21b5f5260045260245ffd5b612162915060203d60201161134f576113418183612a6b565b8461212e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611ff5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121cc6128d2565b6001600160a01b035f54169033820361230b57806001600160a01b03913b156122df57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156105fe575f916122b0575b501561228557805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122d2915060203d6020116122d8575b6122ca8183612a6b565b810190612e0f565b8261223a565b503d6122c0565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761235c61391a565b60405190612369826129f9565b612375816004016128fe565b8252612383602482016128fe565b602083015261239460448201612aa9565b604083015260648101356001600160a01b03811681036102b05760608301526123bf608482016129e2565b60808301526123d060a482016129e2565b60a08301526123e160c48201612d19565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119d66119e1926124256020953690602460048201359101612d43565b60e0840152610104369101612de0565b346102b05760203660031901126102b0576001600160a01b036124566128d2565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248336612912565b91612aff565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124de9061374c565b60058110156109875780602091159081156124ff575b506040519015158152f35b6001915014826124f4565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c168061259f575b61256d575b506001600160801b0360405191168152f35b6125999150805f52600a83526125936001600160801b03600260405f20015416916136bd565b90612adf565b8261255b565b50805f52600a835260ff600160405f20015460a01c1615612556565b346102b05760403660031901126102b0576125d46128d2565b6024356125e08161369c565b331515806126ad575b8061267a575b61264e5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125ef565b50336001600160a01b03821614156125e9565b346102b05760203660031901126102b0576020611744600435612abd565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561278f575b602083108114610b8a57828552908115610b6657506001146127315761057d83610af481850382612a6b565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061277557509091508101602001610af4610ae4565b91926001816020925483858801015201910190929161275d565b91607f1691612705565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612817575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612862575b8115612851575b5083612810565b6301ffc9a760e01b9150148361284a565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612843565b5f5b83811061289d5750505f910152565b818101518382015260200161288e565b906020916128c68151809281855285808601910161288c565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b81811061299a5750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161298d565b359081151582036102b057565b6005111561098757565b610120810190811067ffffffffffffffff821117610fcc57604052565b6060810190811067ffffffffffffffff821117610fcc57604052565b6040810190811067ffffffffffffffff821117610fcc57604052565b610140810190811067ffffffffffffffff821117610fcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610fcc57604052565b67ffffffffffffffff8111610fcc57601f01601f191660200190565b35906001600160801b03821682036102b057565b612ac68161369c565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162457565b91906001600160a01b031680156106f557815f5260036020526001600160a01b0360405f205416151580612d11575b80612cf4575b612ce1577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2c575b6001600160a01b03935085612bf5575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036106c457505050565b612c14825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b94565b9192905080612c8a575b15612c4357828291612b84565b8284612c5b57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cb8575b80612c365750825f526005602052336001600160a01b0360405f20541614612c36565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c95565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b34565b506001612b2e565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fcc5760051b60200190565b929192612d4f82612d2b565b93612d5d6040519586612a6b565b60606020868581520193028201918183116102b057925b828410612d815750505050565b6060848303126102b05760405190612d9882612a16565b612da185612aa9565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612dd060408801612d19565b6040820152815201930192612d74565b91908260409103126102b057604051612df881612a32565b6020808294612e06816128fe565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e375760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612e8d82612a32565b5f6020838281520152565b60405190612ea582612a16565b5f6040838281528260208201520152565b90604051612ec381612a16565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612ef481612d2b565b92612f026040519485612a6b565b81845260208401905f5260205f205f915b838310612f205750505050565b600160208192604051612f3281612a16565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f13565b90612f7b838284612aff565b803b612f88575b50505050565b602091612fce6001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128ad565b03815f865af15f918161303e575b5061300a5750612fea6141c6565b805190816130055782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361302c57505f808080612f82565b633250574960e11b5f5260045260245ffd5b61305891925060203d60201161134f576113418183612a6b565b905f612fdc565b9061306861391a565b815f52600a60205260ff600160405f20015460a81c16156133bc57815f52600a60205260ff600160405f20015460a01c166133a9576001600160a01b038116801561337d576001600160801b03841691821561335157835f5260036020526001600160a01b0360405f205416948583141580613341575b61330d576001600160801b036130f4866141f5565b168085116132da575061311990855f52600a602052600260405f20015460801c61421b565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561315c90612eb6565b6001600160801b036131808160208401511692826040818351169201511690612adf565b1611156132a8575b835f52600a6020526131ac836001600160a01b03600160405f20015416928361464f565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613292575b6132165750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f91613273575b50160361213757808080612f82565b61328c915060203d60201161134f576113418183612a6b565b5f613264565b50835f52600960205260ff60405f20541661320c565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613188565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061334b856140d3565b156130df565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c16156133bc57815f52600a60205260ff600160405f20015460a01c166133a9576001600160a01b038116801561337d576001600160801b03841691821561335157835f5260036020526001600160a01b0360405f20541694858314158061366c575b61330d576001600160801b0361345b866141f5565b168085116132da575061348090855f52600a602052600260405f20015460801c61421b565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134c390612eb6565b6001600160801b036134e78160208401511692826040818351169201511690612adf565b16111561363a575b835f52600a602052613513836001600160a01b03600160405f20015416928361464f565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613615575b61357d5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f916135f6575b5016036135da57808080612f82565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b61360f915060203d60201161134f576113418183612a6b565b5f6135cb565b5060ff613633856001600160a01b03165f52600960205260405f2090565b5416613573565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556134ef565b50613676856140d3565b15613446565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d77575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561374657815f52600a60205264ffffffffff60405f205460c81c16111561372b57805f52600b602052600160405f2054115f146137225761371f906142fb565b90565b61371f9061423b565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f1461376e5750600490565b805f52600a60205260405f205460f81c6137da57805f52600a60205264ffffffffff60405f205460a01c1642106137d5576137a8816136bd565b905f52600a6020526001600160801b0380600260405f200154169116105f146137d057600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613908575b806138eb575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138b4575b168061389c575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613858565b6138d3835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613851565b50805f52600a60205260ff600160405f20015460b01c1615613805565b506001600160a01b03821615156137ff565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361394c57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e375760200190565b8051821015612e375760209160051b010190565b906139b76001600160801b036040840151166020610100850151015190614511565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140ab578015614083578151801561405b577f00000000000000000000000000000000000000000000000000000000000000008111614030575064ffffffffff6040613a2584613974565b51015116811015613fec57505f905f905f81515f905b808210613f64575050505064ffffffffff80421691169081811015613f365750506001600160801b031690818103613f0857505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c108751975f19890190613981565b51015160c81b169360a01b169116171785555f5b818110613dfa575050600187016007556001600160a01b0360208301511680156106f557613c5a886001600160a01b03926137e0565b16613dce578682613ca86001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145ee565b6001600160801b0360208401511680613d9e575b506001600160a01b0381511694613d93613d756001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d1a8b612a32565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061297d565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dc8906001600160a01b036060840151166001600160a01b0361010085015151169033906145ee565b5f613cbc565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e158160e0870151613981565b51825468010000000000000000811015610fcc5760018101808555811015612e37576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c24565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f88906001600160801b03613f7f8588613981565b5151169061421b565b9364ffffffffff806040613f9c8685613981565b51015116941680851115613fb857506001849301909291613a3b565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613ffd84613974565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614119575b508115614100575090565b90506001600160a01b036141143392612abd565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f5565b805f52600a60205261415c600260405f2001612eb6565b90805f52600a60205260ff600160405f20015460a01c165f1461418a5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141a9575061371f906136bd565b61371f91506001600160801b036040818351169201511690612adf565b3d156141f0573d906141d782612a8d565b916141e56040519384612a6b565b82523d5f602084013e565b606090565b61371f9061420281614145565b905f52600a602052600260405f20015460801c90612adf565b906001600160801b03809116911601906001600160801b03821161162457565b5f818152600a60205260409020546142729064ffffffffff60a082901c811660c89290921c8116829003811691428216031661469f565b90805f52600b60205260405f20805415612e37575f526142c767ffffffffffffffff60205f205460801c1692825f52600a6020526142c26001600160801b03600260405f2001541694859261477f565b6147f2565b9182136142e457506142e06001600160801b03916148cd565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061431f82612a4e565b6101206143b260028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eb6565b92019182525f52600b6020526143ca60405f20612ee8565b915f9264ffffffffff60406143de83613974565b510151168664ffffffffff5f925b16106144d2578161446364ffffffffff9697988784816001600160801b0361441b6142c2986144689b9a613981565b5151169a8b9867ffffffffffffffff6020614436868b613981565b51015116978260406144488784613981565b5101511694806144b5575050511680925b031692031661469f565b61477f565b9182136144895750906001600160801b0361448381936148cd565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b0575090565b905090565b60409250906144c7915f190190613981565b510151168092614459565b936001600160801b03600191816144e98886613981565b51511601169401958064ffffffffff8060406145058b87613981565b510151169892986143ec565b91909160405161452081612a32565b5f81525f6020820152926001600160801b0382169081156145d15767016345785d8a0000811161459a5761455c6001600160801b0391836154ea565b1660208501918183521115614586576001600160801b03918261458192511690612adf565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e281612a32565b5f81525f602082015290565b9091926001600160a01b0361464d9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614648608483612a6b565b614902565b565b61464d926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614648606483612a6b565b600160ff1b81148015614772575b61474a575f811215614741576146d1815f035b5f84121561473a57835f0390614987565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470b575f19911813156147065790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614987565b6146d1816146c0565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146ad565b80614799575061479557670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e457806147bc575050670de0b6b3a764000090565b670de0b6b3a764000081146147e0576147db906142c261371f93614a8d565b614be4565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c0575b614898575f81121561488f57614824815f035b5f84121561488857835f03906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614859575f19911813156147065790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ea565b61482481614813565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614800565b5f81126148d75790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492b93169360208151910182865af16149246141c6565b9083615598565b805190811515918261496c575b50506149415750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61497f9250602080918301019101612e0f565b155f80614938565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a525781841015614a1857670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a5f570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a5f576ec097ce7bc90715b34b9f10000000000590565b805f811315614bb957670de0b6b3a76400008112614b9957506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8657506706f05b59d3b20000905b5f8213614b505750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b78575b60011d90614b43565b809192019160011d90614b6f565b9050670de0b6b3a7640000929150020290565b5f1991508015614a5f576ec097ce7bc90715b34b9f100000000005614aaa565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c115768033dd1780914b971141981126137d557614c08905f03614be4565b61371f90614a73565b680a688906bd8affffff81136154bf57670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538a575b670de0b6b3a76400009066ff000000000000831661527a575b65ff00000000008316615172575b64ff000000008316615072575b63ff0000008316614f7a575b62ff00008316614e8a575b61ff008316614da2575b60ff8316614cc2575b029060401c60bf031c90565b60808316614d8f575b60408316614d7c575b60208316614d69575b60108316614d56575b60088316614d43575b60048316614d30575b60028316614d1d575b6001831615614cb657680100000000000000010260401c614cb6565b680100000000000000010260401c614d01565b680100000000000000030260401c614cf8565b680100000000000000060260401c614cef565b6801000000000000000b0260401c614ce6565b680100000000000000160260401c614cdd565b6801000000000000002c0260401c614cd4565b680100000000000000590260401c614ccb565b6180008316614e77575b6140008316614e64575b6120008316614e51575b6110008316614e3e575b6108008316614e2b575b6104008316614e18575b6102008316614e05575b610100831615614cad57680100000000000000b10260401c614cad565b680100000000000001630260401c614de8565b680100000000000002c60260401c614dde565b6801000000000000058c0260401c614dd4565b68010000000000000b170260401c614dca565b6801000000000000162e0260401c614dc0565b68010000000000002c5d0260401c614db6565b680100000000000058b90260401c614dac565b628000008316614f67575b624000008316614f54575b622000008316614f41575b621000008316614f2e575b620800008316614f1b575b620400008316614f08575b620200008316614ef5575b62010000831615614ca3576801000000000000b1720260401c614ca3565b680100000000000162e40260401c614ed7565b6801000000000002c5c80260401c614ecc565b68010000000000058b910260401c614ec1565b680100000000000b17210260401c614eb6565b68010000000000162e430260401c614eab565b680100000000002c5c860260401c614ea0565b6801000000000058b90c0260401c614e95565b6380000000831661505f575b6340000000831661504c575b63200000008316615039575b63100000008316615026575b63080000008316615013575b63040000008316615000575b63020000008316614fed575b6301000000831615614c985768010000000000b172180260401c614c98565b6801000000000162e4300260401c614fce565b68010000000002c5c8600260401c614fc2565b680100000000058b90c00260401c614fb6565b6801000000000b17217f0260401c614faa565b680100000000162e42ff0260401c614f9e565b6801000000002c5c85fe0260401c614f92565b68010000000058b90bfc0260401c614f86565b648000000000831661515f575b644000000000831661514c575b6420000000008316615139575b6410000000008316615126575b6408000000008316615113575b6404000000008316615100575b64020000000083166150ed575b640100000000831615614c8c57680100000000b17217f80260401c614c8c565b68010000000162e42ff10260401c6150cd565b680100000002c5c85fe30260401c6150c0565b6801000000058b90bfce0260401c6150b3565b68010000000b17217fbb0260401c6150a6565b6801000000162e42fff00260401c615099565b68010000002c5c8601cc0260401c61508c565b680100000058b90c0b490260401c61507f565b658000000000008316615267575b654000000000008316615254575b652000000000008316615241575b65100000000000831661522e575b65080000000000831661521b575b650400000000008316615208575b6502000000000083166151f5575b65010000000000831615614c7f576801000000b1721835510260401c614c7f565b680100000162e430e5a20260401c6151d4565b6801000002c5c863b73f0260401c6151c6565b68010000058b90cf1e6e0260401c6151b8565b680100000b1721bcfc9a0260401c6151aa565b68010000162e43f4f8310260401c61519c565b680100002c5c89d5ec6d0260401c61518e565b6801000058b91b5bc9ae0260401c615180565b66800000000000008316615377575b66400000000000008316615364575b66200000000000008316615351575b6610000000000000831661533e575b6608000000000000831661532b575b66040000000000008316615318575b66020000000000008316615305575b6601000000000000831615614c715768010000b17255775c040260401c614c71565b6801000162e525ee05470260401c6152e3565b68010002c5cc37da94920260401c6152d4565b680100058ba01fb9f96d0260401c6152c5565b6801000b175effdc76ba0260401c6152b6565b680100162f3904051fa10260401c6152a7565b6801002c605e2e8cec500260401c615298565b68010058c86da1c09ea20260401c615289565b67800000000000000082166154a0575b670de0b6b3a764000090674000000000000000831661548d575b672000000000000000831661547a575b6710000000000000008316615467575b6708000000000000008316615454575b6704000000000000008316615441575b670200000000000000831661542e575b670100000000000000831661541b575b9050614c58565b680100b1afa5abcbed610260401c615414565b68010163da9fb33356d80260401c615404565b680102c9a3e778060ee70260401c6153f4565b6801059b0d31585743ae0260401c6153e4565b68010b5586cf9890f62a0260401c6153d4565b6801172b83c7d517adce0260401c6153c4565b6801306fe0a31b7152df0260401c6153b4565b5077b504f333f9de64848000000000000000000000000000000061539a565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558757670de0b6b3a7640000821015615557577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d557508051156155ad57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561b575b6155e6575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155de56fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614ac66040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146dd90816103e9823960805181613a310152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a557508063027b67441461308357806306fdde0314612fc8578063081812fc14612faa578063095ea7b314612ea55780631400ecec14612df45780631c1cdd4c14612d905780631e99d56914612d7357806323b872dd14612d5c578063303acc8514612d1f578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131d2565b90610288613334565b610290613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c85614271565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f2001613600565b6001600160801b036103b6816020840151169282604081835116920151169061336c565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f6565b810190613736565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a81565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131d2565b906106eb81614271565b6106f3613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f85614271565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f2001613600565b6001600160801b03610819816020840151169282604081835116920151169061336c565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f6565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a81565b1561076a565b346105f05760403660031901126105f0576109916131bc565b6001600160a01b036109a16131d2565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091614271565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613756565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613197565b0390f35b503d805f833e610b5681836132f6565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613318565b91610b9c60405193846132f6565b838352602084830101116105f057610b4292610bbe9160208085019101613176565b610b2a565b346105f05760403660031901126105f057600435610bdf6131d2565b90610be8613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c3283614271565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ed565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a27565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d4385614271565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f2001613600565b6001600160801b03610ddd816020840151169282604081835116920151169061336c565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614297565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f6565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a81565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131bc565b6110ba6131d2565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613318565b926110f560405194856132f6565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613646565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613859565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a27565b6111f46135e2565b64ffffffffff421680825264ffffffffff61120d613632565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613253565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132da565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b77565b604051908152f35b64ffffffffff611336613632565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131bc565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f6565b604051918291602083526020830190613197565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613859565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f610160604051611643816132a0565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135e2565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132bd565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c161515845201613600565b610120830190815261177187613859565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f7816132a0565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f057611938903690600401613222565b90611941613a27565b5f915b80831061194d57005b6119588382846135be565b3592611962613a27565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613777565b90805f52600a602052611a07600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b94818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614297565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f6565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a27565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613859565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131bc565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131bc565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613756565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135e2565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613284565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a27565b60405161211581613253565b61211d6131bc565b81526121276131d2565b6020820152612134613334565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613284565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132da565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b77565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b903690600401613222565b60243567ffffffffffffffff81116105f05761226b903690600401613222565b612276939193613a27565b8083036125b8575f5b83811061228857005b6122938185856135be565b3561229f8286866135be565b355f5260036020526001600160a01b0360405f205416906122c18385896135be565b356001600160801b038116908181036105f057506122dd613a27565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b0361235484614271565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f2001613600565b6001600160801b036123ee816020840151169282604081835116920151169061336c565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614297565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f6565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a81565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af3565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613859565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a81565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e8565b906040519261289d6020856132f6565b5f8452613646565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a27565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613777565b90805f52600a6020526129b2600260405f2001613600565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a0694818851160316950151169061336c565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614297565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131bc565b6001600160a01b035f541690338203612d0857806001600160a01b03913b15612cdc57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612cad575b5015612c82576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccf915060203d602011612cd5575b612cc781836132f6565b8101906135a6565b82612c34565b503d612cbd565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d406131bc565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6d366131e8565b9161338c565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc890613859565b60058110156111be578060209115908115612de9575b506040519015158152f35b600191501482612dde565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e89575b612e57575b506001600160801b0360405191168152f35b612e839150805f52600a8352612e7d6001600160801b03600260405f2001541691613777565b9061336c565b82612e45565b50805f52600a835260ff600160405f20015460a01c1615612e40565b346105f05760403660031901126105f057612ebe6131bc565b602435612eca81613756565b33151580612f97575b80612f64575b612f385781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed9565b50336001600160a01b0382161415612ed3565b346105f05760203660031901126105f057602061201860043561334a565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613079575b6020831081146115325782855290811561150e575060011461301b57610b428361149c818503826132f6565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305f5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613047565b91607f1691612fef565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f490649060000000000000000000000000000000000000000000000000000000060209314908115613101575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561314c575b811561313b575b50836130fa565b6301ffc9a760e01b91501483613134565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312d565b5f5b8381106131875750505f910152565b8181015183820152602001613178565b906020916131b081518092818552858086019101613176565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761327057604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761327057604052565b610180810190811067ffffffffffffffff82111761327057604052565b610140810190811067ffffffffffffffff82111761327057604052565b6040810190811067ffffffffffffffff82111761327057604052565b90601f8019910116810190811067ffffffffffffffff82111761327057604052565b67ffffffffffffffff811161327057601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335381613756565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359e575b80613581575b61356e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b9575b6001600160a01b03935085613482575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b6134a1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613421565b9192905080613517575b156134d057828291613411565b82846134e857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613545575b806134c35750825f526005602052336001600160a01b0360405f205416146134c3565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613522565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133c1565b5060016133bb565b908160209103126105f0575180151581036105f05790565b91908110156135ce5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ef82613284565b5f6040838281528260208201520152565b9060405161360d81613284565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061365283828461338c565b803b61365f575b50505050565b6020916136a56001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613197565b03815f865af15f9181613715575b506136e157506136c1614242565b805190816136dc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370357505f808080613659565b633250574960e11b5f5260045260245ffd5b61372f91925060203d6020116104f2576104e481836132f6565b905f6136b3565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384f575b61384957815f52600a60205264ffffffffff60405f205460c81c16908142101561382c57806137de9203904203614425565b815f52600a6020526138016001600160801b03600260405f200154168092614511565b908111613816576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b50428110156137ac565b805f52600a60205260ff600160405f20015460a01c165f1461387b5750600490565b805f52600a60205260405f205460f81c6138e757805f52600a60205264ffffffffff60405f205460a01c1642106138e2576138b581613777565b905f52600a6020526001600160801b0380600260405f200154169116105f146138dd57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a15575b806139f8575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139c1575b16806139a9575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613965565b6139e0835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395e565b50805f52600a60205260ff600160405f20015460b01c1615613912565b506001600160a01b038216151561390c565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5957565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac7575b508115613aae575090565b90506001600160a01b03613ac2339261334a565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa3565b805f52600a602052613b0a600260405f2001613600565b90805f52600a60205260ff600160405f20015460a01c165f14613b385750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b5a5750613b5790613777565b90565b613b5791506001600160801b03604081835116920151169061336c565b90613b986001600160801b03604084015116602060e08501510151906142ee565b916001600160801b0383511660c0820151901561421a5764ffffffffff815116156141f2576020810164ffffffffff81511680614166575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413857505064ffffffffff804216915116908181101561410a5750506007549280516001600160801b03169160405192613c2884613284565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8e896132bd565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0e91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140ea575b50600185016007556001600160a01b036020820151168015610cb357613f7c866001600160a01b03926138ed565b166140be57613fa76001600160a01b036060830151166001600160801b0384511690309033906143cb565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408f575b506140866001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b8906001600160a01b036060880151166001600160a01b0360e089015151169033906143cb565b5f613fe2565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4e565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c457505064ffffffffff90511664ffffffffff60408301511690818110613bd0577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561426c573d9061425382613318565b9161426160405193846132f6565b82523d5f602084013e565b606090565b613b579061427e81613af3565b905f52600a602052600260405f20015460801c9061336c565b6142ec926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e76064836132f6565b6145bf565b565b9190916040516142fd816132da565b5f81525f6020820152926001600160801b0382169081156143ae5767016345785d8a00008111614377576143396001600160801b039183614511565b1660208501918183521115614363576001600160801b03918261435e9251169061336c565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143bf816132da565b5f81525f602082015290565b9091926001600160a01b036142ec9481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e76084836132f6565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144f057818410156144b657670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fd570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ae57670de0b6b3a764000082101561457e577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e893169360208151910182865af16145e1614242565b9083614644565b8051908115159182614629575b50506145fe5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463c92506020809183010191016135a6565b155f806145f5565b90614681575080511561465957805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c7575b614692575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468a56fea164736f6c634300081a000a"; + hex"60a0604052346103bf57614ac36040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146da90816103e9823960805181613a2e0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a257508063027b67441461308057806306fdde0314612fc5578063081812fc14612fa7578063095ea7b314612ea25780631400ecec14612df15780631c1cdd4c14612d8d5780631e99d56914612d7057806323b872dd14612d59578063303acc8514612d1c578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131cf565b90610288613331565b610290613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c8561426e565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016135fd565b6001600160801b036103b68160208401511692826040818351169201511690613369565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f3565b810190613733565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a7e565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131cf565b906106eb8161426e565b6106f3613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f8561426e565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f20016135fd565b6001600160801b036108198160208401511692826040818351169201511690613369565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f3565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a7e565b1561076a565b346105f05760403660031901126105f0576109916131b9565b6001600160a01b036109a16131cf565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b60209161426e565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613753565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613194565b0390f35b503d805f833e610b5681836132f3565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613315565b91610b9c60405193846132f3565b838352602084830101116105f057610b4292610bbe9160208085019101613173565b610b2a565b346105f05760403660031901126105f057600435610bdf6131cf565b90610be8613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c328361426e565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ea565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a24565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d438561426e565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f20016135fd565b6001600160801b03610ddd8160208401511692826040818351169201511690613369565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614294565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f3565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a7e565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131b9565b6110ba6131cf565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613315565b926110f560405194856132f3565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613643565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613856565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a24565b6111f46135df565b64ffffffffff421680825264ffffffffff61120d61362f565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613250565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132d7565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b74565b604051908152f35b64ffffffffff61133661362f565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131b9565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f3565b604051918291602083526020830190613194565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613856565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f6101606040516116438161329d565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135df565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132ba565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016135fd565b610120830190815261177187613856565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f78161329d565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f05761193890369060040161321f565b90611941613a24565b5f915b80831061194d57005b6119588382846135bb565b3592611962613a24565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613774565b90805f52600a602052611a07600260405f20016135fd565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b948188511603169501511690613369565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614294565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f3565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a24565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613856565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131b9565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131b9565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613753565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135df565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613281565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a24565b60405161211581613250565b61211d6131b9565b81526121276131cf565b6020820152612134613331565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613281565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132d7565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b74565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b90369060040161321f565b60243567ffffffffffffffff81116105f05761226b90369060040161321f565b612276939193613a24565b8083036125b8575f5b83811061228857005b6122938185856135bb565b3561229f8286866135bb565b355f5260036020526001600160a01b0360405f205416906122c18385896135bb565b356001600160801b038116908181036105f057506122dd613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b036123548461426e565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f20016135fd565b6001600160801b036123ee8160208401511692826040818351169201511690613369565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f3565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a7e565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af0565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613856565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a7e565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e5565b906040519261289d6020856132f3565b5f8452613643565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613774565b90805f52600a6020526129b2600260405f20016135fd565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a06948188511603169501511690613369565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614294565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131b9565b6001600160a01b035f541690338203612d0557806001600160a01b03913b15612cd957166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612caa575b5015612c7f57805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccc915060203d602011612cd2575b612cc481836132f3565b8101906135a3565b82612c34565b503d612cba565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d3d6131b9565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6a366131e5565b91613389565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc590613856565b60058110156111be578060209115908115612de6575b506040519015158152f35b600191501482612ddb565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e86575b612e54575b506001600160801b0360405191168152f35b612e809150805f52600a8352612e7a6001600160801b03600260405f2001541691613774565b90613369565b82612e42565b50805f52600a835260ff600160405f20015460a01c1615612e3d565b346105f05760403660031901126105f057612ebb6131b9565b602435612ec781613753565b33151580612f94575b80612f61575b612f355781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed6565b50336001600160a01b0382161415612ed0565b346105f05760203660031901126105f0576020612018600435613347565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613076575b6020831081146115325782855290811561150e575060011461301857610b428361149c818503826132f3565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305c5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613044565b91607f1691612fec565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f4906490600000000000000000000000000000000000000000000000000000000602093149081156130fe575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613149575b8115613138575b50836130f7565b6301ffc9a760e01b91501483613131565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312a565b5f5b8381106131845750505f910152565b8181015183820152602001613175565b906020916131ad81518092818552858086019101613173565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761326d57604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761326d57604052565b610180810190811067ffffffffffffffff82111761326d57604052565b610140810190811067ffffffffffffffff82111761326d57604052565b6040810190811067ffffffffffffffff82111761326d57604052565b90601f8019910116810190811067ffffffffffffffff82111761326d57604052565b67ffffffffffffffff811161326d57601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335081613753565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359b575b8061357e575b61356b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b6575b6001600160a01b0393508561347f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b61349e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561341e565b9192905080613514575b156134cd5782829161340e565b82846134e557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613542575b806134c05750825f526005602052336001600160a01b0360405f205416146134c0565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541661351f565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133be565b5060016133b8565b908160209103126105f0575180151581036105f05790565b91908110156135cb5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ec82613281565b5f6040838281528260208201520152565b9060405161360a81613281565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061364f838284613389565b803b61365c575b50505050565b6020916136a26001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613194565b03815f865af15f9181613712575b506136de57506136be61423f565b805190816136d95782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370057505f808080613656565b633250574960e11b5f5260045260245ffd5b61372c91925060203d6020116104f2576104e481836132f3565b905f6136b0565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384c575b61384657815f52600a60205264ffffffffff60405f205460c81c16908142101561382957806137db9203904203614422565b815f52600a6020526137fe6001600160801b03600260405f20015416809261450e565b908111613813576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b50428110156137a9565b805f52600a60205260ff600160405f20015460a01c165f146138785750600490565b805f52600a60205260405f205460f81c6138e457805f52600a60205264ffffffffff60405f205460a01c1642106138df576138b281613774565b905f52600a6020526001600160801b0380600260405f200154169116105f146138da57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a12575b806139f5575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139be575b16806139a6575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613962565b6139dd835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395b565b50805f52600a60205260ff600160405f20015460b01c161561390f565b506001600160a01b0382161515613909565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac4575b508115613aab575090565b90506001600160a01b03613abf3392613347565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa0565b805f52600a602052613b07600260405f20016135fd565b90805f52600a60205260ff600160405f20015460a01c165f14613b355750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b575750613b5490613774565b90565b613b5491506001600160801b036040818351169201511690613369565b90613b956001600160801b03604084015116602060e08501510151906142eb565b916001600160801b0383511660c082015190156142175764ffffffffff815116156141ef576020810164ffffffffff81511680614163575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413557505064ffffffffff80421691511690818110156141075750506007549280516001600160801b03169160405192613c2584613281565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8b896132ba565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0b91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140e7575b50600185016007556001600160a01b036020820151168015610cb357613f79866001600160a01b03926138ea565b166140bb57613fa46001600160a01b036060830151166001600160801b0384511690309033906143c8565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408c575b506140836001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b5906001600160a01b036060880151166001600160a01b0360e089015151169033906143c8565b5f613fdf565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4b565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c157505064ffffffffff90511664ffffffffff60408301511690818110613bcd577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614269573d9061425082613315565b9161425e60405193846132f3565b82523d5f602084013e565b606090565b613b549061427b81613af0565b905f52600a602052600260405f20015460801c90613369565b6142e9926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e46064836132f3565b6145bc565b565b9190916040516142fa816132d7565b5f81525f6020820152926001600160801b0382169081156143ab5767016345785d8a00008111614374576143366001600160801b03918361450e565b1660208501918183521115614360576001600160801b03918261435b92511690613369565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143bc816132d7565b5f81525f602082015290565b9091926001600160a01b036142e99481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e46084836132f3565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144ed57818410156144b357670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fa570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ab57670de0b6b3a764000082101561457b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e593169360208151910182865af16145de61423f565b9083614641565b8051908115159182614626575b50506145fb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463992506020809183010191016135a3565b155f806145f2565b9061467e575080511561465657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c4575b61468f575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468756fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e457614da86060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a052600160075561499a908161040e823960805181613dac015260a051818181612f330152613e550152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461329f57508063027b67441461327d57806306fdde03146131c2578063081812fc146131a4578063095ea7b31461309f5780631400ecec14612fee5780631c1cdd4c14612f8a5780631e99d56914612f6d57806323b872dd14612f565780632fe4304114612f1c578063303acc8514612edf57806332fbe22b14612d82578063406887cb14612c1057806340e58ee514612958578063425d30dd1461290857806342842e0e146128df57806342966c681461271b57806344267570146126f55780634857501f146126845780634869e12d1461264a5780634cc55e111461229157806357404b12146122035780636352211e146121d45780636d0cee75146121d457806370a082311461216a57806375829def146120fc5780637cad6cd11461200b5780637de6b1db14611ebe5780637f5799f914611e655780638659c27014611aae578063894e9a0d1461176f578063897f362b146114a45780638f69b993146114245780639067b677146113d557806395d89b41146112cd578063a22cb46514611219578063a80fc071146111c8578063ad35efd414611169578063b256456914611119578063b88d4fde1461108f578063b8a3be661461105a578063b971302a1461100c578063bc2be1be14610fbd578063c156a11d14610bc9578063c87b56dd14610abe578063d4dbd20b14610a6d578063d511609f14610a22578063d975dfed146109d7578063e985e9c51461097e578063ea5ead19146106a9578063eac8f5b814610658578063f590c176146105fd578063f851a440146105d85763fdd46d601461026e575f80fd5b346105d45760603660031901126105d45760043561028a6133cc565b90604435916001600160801b038316908184036105d4576102a9613da2565b825f52600a60205260ff600160405f20015460a81c16156105c257825f52600a60205260ff600160405f20015460a01c166105af576001600160a01b03811690811561059c57821561058957835f5260036020526001600160a01b0360405f205416948583141580610579575b61055e576001600160801b0361032b866145fa565b16808511610544575061035090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a90613948565b6001600160801b036103ae81602084015116928260408183511692015116906135a3565b161115610512575b835f52600a6020526103da836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104fc575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916104c2575b50160361049757005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104e4915060203d6020116104ea575b6104dc818361352f565b810190613a8b565b5f61048e565b503d6104d2565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b50610583856144d5565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d4575f3660031901126105d45760206001600160a01b035f5416604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d45760403660031901126105d4576004356106c56133cc565b906106cf816145fa565b916106d8613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959576001600160a01b0381168015610946576001600160801b03841691821561058957835f5260036020526001600160a01b0360405f205416948583141580610936575b61055e576001600160801b03610764866145fa565b16808511610544575061078990855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107c390613948565b6001600160801b036107e781602084015116928260408183511692015116906135a3565b161115610904575b835f52600a602052610813836001600160a01b03600160405f20015416928361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806108ee575b61087957005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916108cf5750160361049757005b6108e8915060203d6020116104ea576104dc818361352f565b8461048e565b50835f52600960205260ff60405f205416610873565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107ef565b50610940856144d5565b1561074f565b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105d45760403660031901126105d4576109976133b6565b6001600160a01b036109a76133cc565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a116020916145fa565b6001600160801b0360405191168152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a6020526020600260405f20015460801c604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d45760203660031901126105d457600435610adb81613aab565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f1575f90610b4c575b610b4890604051918291602083526020830190613391565b0390f35b503d805f833e610b5c818361352f565b8101906020818303126105d45780519067ffffffffffffffff82116105d457019080601f830112156105d457815191610b9483613551565b91610ba2604051938461352f565b838352602084830101116105d457610b4892610bc49160208085019101613370565b610b30565b346105d45760403660031901126105d457600435610be56133cc565b90610bee613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f5260036020526001600160a01b0360405f20541691823303610fa657610c30826145fa565b6001600160801b03811680158015610cce575b5050506001600160a01b03811615610cbb57610c67826001600160a01b0392613c68565b169182610c815750637e27328960e01b5f5260045260245ffd5b808303610c8a57005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cd6613da2565b845f52600a60205260ff600160405f20015460a81c1615610f9457845f52600a60205260ff600160405f20015460a01c16610f81578515610f6e5761058957835f5260036020526001600160a01b0360405f205416918286141580610f5e575b610f43576001600160801b03610d4b866145fa565b16808311610f295750610d7090855f52600a602052600260405f20015460801c614620565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610daa90613948565b6001600160801b03610dce81602084015116928260408183511692015116906135a3565b161115610ef7575b835f52600a6020526001600160a01b03600160405f20015416610dfa82878361477e565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610ee1575b610e65575b80610c43565b604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91610ec2575b5016036104975780610e5f565b610edb915060203d6020116104ea576104dc818361352f565b87610eb5565b50815f52600960205260ff60405f205416610e5a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610dd6565b828663287ecaef60e21b5f5260045260245260445260645ffd5b858563b34359d360e01b5f526004523360245260445260645ffd5b50610f68856144d5565b15610d36565b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d45760203660031901126105d4576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d45760803660031901126105d4576110a86133b6565b6110b06133cc565b6064359167ffffffffffffffff83116105d457366023840112156105d4578260040135916110dd83613551565b926110eb604051948561352f565b80845236602482870101116105d4576020815f926024611117980183880137850101526044359161399b565b005b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576111a190613bd4565b60405160058210156111b4576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d45760403660031901126105d4576112326133b6565b602435908115158092036105d4576001600160a01b03169081156112a157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4575f3660031901126105d4576040515f6002548060011c906001811680156113cb575b6020831081146113b7578285529081156113935750600114611335575b610b48836113218185038261352f565b604051918291602083526020830190613391565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061137957509091508101602001611321611311565b919260018160209254838588010152019101909291611361565b60ff191660208086019190915291151560051b840190910191506113219050611311565b634e487b7160e01b5f52602260045260245ffd5b91607f16916112f4565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c16156106475761145c90613bd4565b6005811015806111b45760028214908115611498575b8115611486575b6020826040519015158152f35b90506111b45760046020911482611479565b5050600381145f611472565b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d4578036036101206003198201126105d4576114df613da2565b60c482013590602219018112156105d45781019060048201359167ffffffffffffffff83116105d45760248101908360061b80360383136105d4576004602091611528876137ef565b96611536604051988961352f565b875282870193010101913683116105d457905b8282106117555750505081519161155f836137ef565b9261156d604051948561352f565b808452601f1961157c826137ef565b015f5b81811061173257505064ffffffffff4216916001600160801b036115a282613acc565b51511664ffffffffff8060206115b785613acc565b51015116850116604051916115cb836134da565b825260208201526115db86613acc565b526115e585613acc565b5060015b8281106116bd575050506115ff8260040161397a565b9261160c6024840161397a565b92611619604482016138a8565b916064820135936001600160a01b0385168095036105d4576020966116b596611675966001600160801b036116aa976001600160a01b0361165c60848a0161398e565b948161166a60a48c0161398e565b976040519d8e6134bd565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161383d565b610100820152613dfc565b604051908152f35b806001600160801b036116d260019385613ad9565b51511664ffffffffff8060206116eb5f1986018c613ad9565b510151168160206116fc8689613ad9565b5101511601166040519161170f836134da565b825260208201526117208289613ad9565b5261172b8188613ad9565b50016115e9565b602090604051611741816134da565b5f81525f838201528282890101520161157f565b60206040916117643685613807565b815201910190611549565b346105d45760203660031901126105d4576004356060610160604051611794816134f6565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201526040516117da81613513565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611a9a576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b03851687526118d7600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c161515885201613948565b6101208b019081526118e889613bd4565b60058110156111b457600214611a92575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119678c6134f6565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b019889526119bb906138d4565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b4891613461565b5f87526118f9565b634e487b7160e01b5f52604160045260245ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d457611adf903690600401613430565b90611ae8613da2565b5f915b808310611af457005b611aff838284613884565b3592611b09613da2565b835f52600a60205260ff600160405f20015460a81c1615611e5357835f52600a60205260ff600160405f20015460a01c165f14611b535783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611e4157611b88815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57611b9681613aed565b90805f52600a602052611bae600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081611c029481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611de0575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d146001600160a01b03600160405f2001541694611cec88858861477e565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611d65575b50505050506001019190611aeb565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f91611dc2575b5016036104975780808080611d56565b611dda915060203d81116104ea576104dc818361352f565b87611db2565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611c4c565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600b602052610b48611eaa60405f206138d4565b604051918291602083526020830190613461565b346105d45760203660031901126105d457600435611eda613da2565b805f52600a60205260ff600160405f20015460a81c161561064757611efe81613bd4565b60058110156111b45760048103611f225750634a5541ef60e01b5f5260045260245ffd5b60038103611f3d575063fe19f19f60e01b5f5260045260245ffd5b600214611ff957611f62815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57805f52600a60205260ff60405f205460f01c1615611fe7576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d45760203660031901126105d4576004356001600160a01b0381168091036105d4576001600160a01b035f54163381036120e6575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120d25760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d4576121156133b6565b5f546001600160a01b0381163381036120e657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d45760203660031901126105d4576001600160a01b0361218b6133b6565b1680156121a8575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d45760203660031901126105d45760206121f2600435613aab565b6001600160a01b0360405191168152f35b346105d45760203660031901126105d45760043561221f6138bc565b50805f52600a60205260ff600160405f20015460a81c1615610647575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c16612269836134da565b8252602082015261228f8251809264ffffffffff60208092828151168552015116910152565bf35b346105d45760403660031901126105d45760043567ffffffffffffffff81116105d4576122c2903690600401613430565b9060243567ffffffffffffffff81116105d4576122e3903690600401613430565b9190926122ee613da2565b82810361261a575f5b81811061230057005b61230b818385613884565b35612317828486613884565b355f5260036020526001600160a01b0360405f2054169061234161233c84888a613884565b6138a8565b9161234a613da2565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959578015612607576001600160801b0383169081156125f457825f5260036020526001600160a01b0360405f2054169384821415806125e4575b6125c9576001600160801b036123cc856145fa565b168084116125af57506123f190845f52600a602052600260405f20015460801c614620565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561242b90613948565b6001600160801b0361244f81602084015116928260408183511692015116906135a3565b16111561257d575b825f52600a6020526001600160a01b03600160405f2001541661247b83838361477e565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612567575b6124ec575b505050506001016122f7565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91612549575b501603610497578080806124e0565b612561915060203d81116104ea576104dc818361352f565b8961253a565b50835f52600960205260ff60405f2054166124db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612457565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506125ee846144d5565b156123b7565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a11602091614547565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f6126bd82613bd4565b60058110156111b4576002036126db575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126ce565b346105d4575f3660031901126105d45760206001600160a01b0360085416604051908152f35b346105d45760203660031901126105d457600435612737613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c16156128b457612776816144d5565b15611e2b57805f5260036020526001600160a01b0360405f2054161515806128ad575b80612890575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612847575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061283557005b637e27328960e01b5f5260045260245ffd5b612866835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f1981540190556127ed565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561279f565b505f612799565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4576111176128f0366133f6565b906040519261290060208561352f565b5f845261399b565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d45760203660031901126105d457600435612974613da2565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c165f146129bd57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611e41576129ef815f52600a6020526001600160a01b0360405f205416331490565b15611e2b576129fd81613aed565b90805f52600a602052612a15600260405f2001613948565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081612a699481885116031695015116906135a3565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612beb575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b536001600160a01b03600160405f2001541694611cec88858861477e565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b9657005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f916108cf5750160361049757005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ab3565b346105d45760203660031901126105d457612c296133b6565b6001600160a01b035f541690338203612d6b57806001600160a01b03913b15612d3f57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f1575f91612d10575b5015612ce5576040817fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd72801925f526009602052815f20600160ff198254161790558151903382526020820152a1005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d32915060203d602011612d38575b612d2a818361352f565b81019061386c565b82612c97565b503d612d20565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d45761014060031982360301126105d457612dbc613da2565b604051612dc8816134bd565b612dd4826004016133e2565b8152612de2602483016133e2565b6020820152612df36044830161356d565b604082015260648201356001600160a01b03811681036105d4576060820152612e1e608483016134b0565b6080820152612e2f60a483016134b0565b60a0820152612e4060c483016137dd565b60c082015260e482013567ffffffffffffffff81116105d457820191366023840112156105d457600483013592612e76846137ef565b90612e84604051928361352f565b848252602060048184019660061b83010101903682116105d457602401945b818610612ec55760206116b5866116aa878760e084015261010436910161383d565b6020604091612ed43689613807565b815201950194612ea3565b346105d45760203660031901126105d4576001600160a01b03612f006133b6565b165f526009602052602060ff60405f2054166040519015158152f35b346105d4575f3660031901126105d45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105d457611117612f67366133f6565b916135c3565b346105d4575f3660031901126105d4576020600754604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757612fc290613bd4565b60058110156111b4578060209115908115612fe3575b506040519015158152f35b600191501482612fd8565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576020905f90805f52600a835260ff60405f205460f01c1680613083575b613051575b506001600160801b0360405191168152f35b61307d9150805f52600a83526130776001600160801b03600260405f2001541691613aed565b906135a3565b8261303f565b50805f52600a835260ff600160405f20015460a01c161561303a565b346105d45760403660031901126105d4576130b86133b6565b6024356130c481613aab565b33151580613191575b8061315e575b6131325781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156130d3565b50336001600160a01b03821614156130cd565b346105d45760203660031901126105d45760206121f2600435613581565b346105d4575f3660031901126105d4576040515f6001548060011c90600181168015613273575b6020831081146113b757828552908115611393575060011461321557610b48836113218185038261352f565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061325957509091508101602001611321611311565b919260018160209254838588010152019101909291613241565b91607f16916131e9565b346105d4575f3660031901126105d457602060405167016345785d8a00008152f35b346105d45760203660031901126105d457600435906001600160e01b031982168092036105d457817f4906490600000000000000000000000000000000000000000000000000000000602093149081156132fb575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613346575b8115613335575b50836132f4565b6301ffc9a760e01b9150148361332e565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613327565b5f5b8381106133815750505f910152565b8181015183820152602001613372565b906020916133aa81518092818552858086019101613370565b601f01601f1916010190565b600435906001600160a01b03821682036105d457565b602435906001600160a01b03821682036105d457565b35906001600160a01b03821682036105d457565b60609060031901126105d4576004356001600160a01b03811681036105d457906024356001600160a01b03811681036105d4579060443590565b9181601f840112156105d45782359167ffffffffffffffff83116105d4576020808501948460051b0101116105d457565b90602080835192838152019201905f5b81811061347e5750505090565b825180516001600160801b0316855260209081015164ffffffffff168186015260409094019390920191600101613471565b359081151582036105d457565b610120810190811067ffffffffffffffff821117611a9a57604052565b6040810190811067ffffffffffffffff821117611a9a57604052565b610180810190811067ffffffffffffffff821117611a9a57604052565b6060810190811067ffffffffffffffff821117611a9a57604052565b90601f8019910116810190811067ffffffffffffffff821117611a9a57604052565b67ffffffffffffffff8111611a9a57601f01601f191660200190565b35906001600160801b03821682036105d457565b61358a81613aab565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116120d257565b91906001600160a01b03168015610cbb57815f5260036020526001600160a01b0360405f2054161515806137d5575b806137b8575b6137a5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836136f0575b6001600160a01b039350856136b9575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8a57505050565b6136d8825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613658565b919290508061374e575b1561370757828291613648565b828461371f57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b50338414801561377c575b806136fa5750825f526005602052336001600160a01b0360405f205416146136fa565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613759565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156135f8565b5060016135f2565b359064ffffffffff821682036105d457565b67ffffffffffffffff8111611a9a5760051b60200190565b91908260409103126105d45760405161381f816134da565b60206138388183956138308161356d565b8552016137dd565b910152565b91908260409103126105d457604051613855816134da565b6020808294613863816133e2565b84520135910152565b908160209103126105d4575180151581036105d45790565b91908110156138945760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105d45790565b604051906138c9826134da565b5f6020838281520152565b9081546138e0816137ef565b926138ee604051948561352f565b81845260208401905f5260205f205f915b83831061390c5750505050565b60016020819260405161391e816134da565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906138ff565b9060405161395581613513565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105d45790565b3580151581036105d45790565b906139a78382846135c3565b803b6139b4575b50505050565b6020916139fa6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613391565b03815f865af15f9181613a6a575b50613a365750613a166145cb565b80519081613a315782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613a5857505f8080806139ae565b633250574960e11b5f5260045260245ffd5b613a8491925060203d6020116104ea576104dc818361352f565b905f613a08565b908160209103126105d457516001600160e01b0319811681036105d45790565b805f5260036020526001600160a01b0360405f205416908115612835575090565b8051156138945760200190565b80518210156138945760209160051b010190565b9064ffffffffff421691805f52600b602052613b0b60405f206138d4565b908364ffffffffff6020613b1e85613acc565b5101511611613bcd57805f52600a6020528364ffffffffff60405f205460c81c161115613bae57506001600160801b03613b5782613acc565b515116916001925b8251841015613ba7578464ffffffffff6020613b7b8787613ad9565b5101511611613ba7576001600160801b0360019181613b9a8787613ad9565b5151160116930192613b5f565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613bf65750600490565b805f52600a60205260405f205460f81c613c6257805f52600a60205264ffffffffff60405f205460a01c164210613c5d57613c3081613aed565b905f52600a6020526001600160801b0380600260405f200154169116105f14613c5857600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613d90575b80613d73575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613d3c575b1680613d24575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613ce0565b613d5b835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613cd9565b50805f52600a60205260ff600160405f20015460b01c1615613c8d565b506001600160a01b0382161515613c87565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dd457565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613e1e6001600160801b036040840151166020610100850151015190614640565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156144ad578015614485578151801561445d577f00000000000000000000000000000000000000000000000000000000000000008111614432575064ffffffffff6020613e8c84613acc565b510151168110156143ee57505f905f905f81515f905b808210614366575050505064ffffffffff804216911690818110156143385750506001600160801b03169081810361430a57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406e8751975f19890190613ad9565b51015160c81b169360a01b169116171785555f5b818110614258575050600187016007556001600160a01b036020830151168015610cbb576140b8886001600160a01b0392613c68565b1661422c5786826141066001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061471d565b6001600160801b03602084015116806141fc575b506001600160a01b03815116946141f16141d36001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141788b6134da565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190613461565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614226906001600160a01b036060840151166001600160a01b03610100850151511690339061471d565b5f61411a565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142738160e0870151613ad9565b5182549268010000000000000000841015611a9a5760018401808255841015613894576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614082565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919350919361438a906001600160801b036143818588613ad9565b51511690614620565b9364ffffffffff80602061439e8685613ad9565b510151169416808511156143ba57506001849301909291613ea2565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff60206143ff84613acc565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561451b575b508115614502575090565b90506001600160a01b036145163392613581565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6144f7565b805f52600a60205261455e600260405f2001613948565b90805f52600a60205260ff600160405f20015460a01c165f1461458c5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6145ae57506145ab90613aed565b90565b6145ab91506001600160801b0360408183511692015116906135a3565b3d156145f5573d906145dc82613551565b916145ea604051938461352f565b82523d5f602084013e565b606090565b6145ab9061460781614547565b905f52600a602052600260405f20015460801c906135a3565b906001600160801b03809116911601906001600160801b0382116120d257565b91909160405161464f816134da565b5f81525f6020820152926001600160801b0382169081156147005767016345785d8a000081116146c95761468b6001600160801b039183614853565b16602085019181835211156146b5576001600160801b0391826146b0925116906135a3565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b5050509050604051614711816134da565b5f81525f602082015290565b9091926001600160a01b0361477c9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261477760848361352f565b6147ce565b565b61477c926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261477760648361352f565b5f806001600160a01b036147f793169360208151910182865af16147f06145cb565b9083614901565b8051908115159182614838575b505061480d5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61484b925060208091830101910161386c565b155f80614804565b9091905f19838209838202918280831092039180830392146148f057670de0b6b3a76400008210156148c0577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061493e575080511561491657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614984575b61494f575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561494756fea164736f6c634300081a000a"; + hex"60c0604052346103e457614da56060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614997908161040e823960805181613da9015260a051818181612f300152613e520152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461329c57508063027b67441461327a57806306fdde03146131bf578063081812fc146131a1578063095ea7b31461309c5780631400ecec14612feb5780631c1cdd4c14612f875780631e99d56914612f6a57806323b872dd14612f535780632fe4304114612f19578063303acc8514612edc57806332fbe22b14612d7f578063406887cb14612c1057806340e58ee514612958578063425d30dd1461290857806342842e0e146128df57806342966c681461271b57806344267570146126f55780634857501f146126845780634869e12d1461264a5780634cc55e111461229157806357404b12146122035780636352211e146121d45780636d0cee75146121d457806370a082311461216a57806375829def146120fc5780637cad6cd11461200b5780637de6b1db14611ebe5780637f5799f914611e655780638659c27014611aae578063894e9a0d1461176f578063897f362b146114a45780638f69b993146114245780639067b677146113d557806395d89b41146112cd578063a22cb46514611219578063a80fc071146111c8578063ad35efd414611169578063b256456914611119578063b88d4fde1461108f578063b8a3be661461105a578063b971302a1461100c578063bc2be1be14610fbd578063c156a11d14610bc9578063c87b56dd14610abe578063d4dbd20b14610a6d578063d511609f14610a22578063d975dfed146109d7578063e985e9c51461097e578063ea5ead19146106a9578063eac8f5b814610658578063f590c176146105fd578063f851a440146105d85763fdd46d601461026e575f80fd5b346105d45760603660031901126105d45760043561028a6133c9565b90604435916001600160801b038316908184036105d4576102a9613d9f565b825f52600a60205260ff600160405f20015460a81c16156105c257825f52600a60205260ff600160405f20015460a01c166105af576001600160a01b03811690811561059c57821561058957835f5260036020526001600160a01b0360405f205416948583141580610579575b61055e576001600160801b0361032b866145f7565b16808511610544575061035090855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a90613945565b6001600160801b036103ae81602084015116928260408183511692015116906135a0565b161115610512575b835f52600a6020526103da836001600160a01b03600160405f20015416928361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104fc575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916104c2575b50160361049757005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104e4915060203d6020116104ea575b6104dc818361352c565b810190613a88565b5f61048e565b503d6104d2565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b50610583856144d2565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d4575f3660031901126105d45760206001600160a01b035f5416604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d45760403660031901126105d4576004356106c56133c9565b906106cf816145f7565b916106d8613d9f565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959576001600160a01b0381168015610946576001600160801b03841691821561058957835f5260036020526001600160a01b0360405f205416948583141580610936575b61055e576001600160801b03610764866145f7565b16808511610544575061078990855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107c390613945565b6001600160801b036107e781602084015116928260408183511692015116906135a0565b161115610904575b835f52600a602052610813836001600160a01b03600160405f20015416928361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806108ee575b61087957005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916108cf5750160361049757005b6108e8915060203d6020116104ea576104dc818361352c565b8461048e565b50835f52600960205260ff60405f205416610873565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107ef565b50610940856144d2565b1561074f565b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105d45760403660031901126105d4576109976133b3565b6001600160a01b036109a76133c9565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a116020916145f7565b6001600160801b0360405191168152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a6020526020600260405f20015460801c604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d45760203660031901126105d457600435610adb81613aa8565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f1575f90610b4c575b610b489060405191829160208352602083019061338e565b0390f35b503d805f833e610b5c818361352c565b8101906020818303126105d45780519067ffffffffffffffff82116105d457019080601f830112156105d457815191610b948361354e565b91610ba2604051938461352c565b838352602084830101116105d457610b4892610bc4916020808501910161336d565b610b30565b346105d45760403660031901126105d457600435610be56133c9565b90610bee613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f5260036020526001600160a01b0360405f20541691823303610fa657610c30826145f7565b6001600160801b03811680158015610cce575b5050506001600160a01b03811615610cbb57610c67826001600160a01b0392613c65565b169182610c815750637e27328960e01b5f5260045260245ffd5b808303610c8a57005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cd6613d9f565b845f52600a60205260ff600160405f20015460a81c1615610f9457845f52600a60205260ff600160405f20015460a01c16610f81578515610f6e5761058957835f5260036020526001600160a01b0360405f205416918286141580610f5e575b610f43576001600160801b03610d4b866145f7565b16808311610f295750610d7090855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610daa90613945565b6001600160801b03610dce81602084015116928260408183511692015116906135a0565b161115610ef7575b835f52600a6020526001600160a01b03600160405f20015416610dfa82878361477b565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610ee1575b610e65575b80610c43565b604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91610ec2575b5016036104975780610e5f565b610edb915060203d6020116104ea576104dc818361352c565b87610eb5565b50815f52600960205260ff60405f205416610e5a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610dd6565b828663287ecaef60e21b5f5260045260245260445260645ffd5b858563b34359d360e01b5f526004523360245260445260645ffd5b50610f68856144d2565b15610d36565b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d45760203660031901126105d4576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d45760803660031901126105d4576110a86133b3565b6110b06133c9565b6064359167ffffffffffffffff83116105d457366023840112156105d4578260040135916110dd8361354e565b926110eb604051948561352c565b80845236602482870101116105d4576020815f9260246111179801838801378501015260443591613998565b005b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576111a190613bd1565b60405160058210156111b4576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d45760403660031901126105d4576112326133b3565b602435908115158092036105d4576001600160a01b03169081156112a157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4575f3660031901126105d4576040515f6002548060011c906001811680156113cb575b6020831081146113b7578285529081156113935750600114611335575b610b48836113218185038261352c565b60405191829160208352602083019061338e565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061137957509091508101602001611321611311565b919260018160209254838588010152019101909291611361565b60ff191660208086019190915291151560051b840190910191506113219050611311565b634e487b7160e01b5f52602260045260245ffd5b91607f16916112f4565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c16156106475761145c90613bd1565b6005811015806111b45760028214908115611498575b8115611486575b6020826040519015158152f35b90506111b45760046020911482611479565b5050600381145f611472565b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d4578036036101206003198201126105d4576114df613d9f565b60c482013590602219018112156105d45781019060048201359167ffffffffffffffff83116105d45760248101908360061b80360383136105d4576004602091611528876137ec565b96611536604051988961352c565b875282870193010101913683116105d457905b8282106117555750505081519161155f836137ec565b9261156d604051948561352c565b808452601f1961157c826137ec565b015f5b81811061173257505064ffffffffff4216916001600160801b036115a282613ac9565b51511664ffffffffff8060206115b785613ac9565b51015116850116604051916115cb836134d7565b825260208201526115db86613ac9565b526115e585613ac9565b5060015b8281106116bd575050506115ff82600401613977565b9261160c60248401613977565b92611619604482016138a5565b916064820135936001600160a01b0385168095036105d4576020966116b596611675966001600160801b036116aa976001600160a01b0361165c60848a0161398b565b948161166a60a48c0161398b565b976040519d8e6134ba565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161383a565b610100820152613df9565b604051908152f35b806001600160801b036116d260019385613ad6565b51511664ffffffffff8060206116eb5f1986018c613ad6565b510151168160206116fc8689613ad6565b5101511601166040519161170f836134d7565b825260208201526117208289613ad6565b5261172b8188613ad6565b50016115e9565b602090604051611741816134d7565b5f81525f838201528282890101520161157f565b60206040916117643685613804565b815201910190611549565b346105d45760203660031901126105d4576004356060610160604051611794816134f3565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201526040516117da81613510565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611a9a576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b03851687526118d7600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c161515885201613945565b6101208b019081526118e889613bd1565b60058110156111b457600214611a92575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119678c6134f3565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b019889526119bb906138d1565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b489161345e565b5f87526118f9565b634e487b7160e01b5f52604160045260245ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d457611adf90369060040161342d565b90611ae8613d9f565b5f915b808310611af457005b611aff838284613881565b3592611b09613d9f565b835f52600a60205260ff600160405f20015460a81c1615611e5357835f52600a60205260ff600160405f20015460a01c165f14611b535783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611e4157611b88815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57611b9681613aea565b90805f52600a602052611bae600260405f2001613945565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081611c029481885116031695015116906135a0565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611de0575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d146001600160a01b03600160405f2001541694611cec88858861477b565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611d65575b50505050506001019190611aeb565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f91611dc2575b5016036104975780808080611d56565b611dda915060203d81116104ea576104dc818361352c565b87611db2565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611c4c565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600b602052610b48611eaa60405f206138d1565b60405191829160208352602083019061345e565b346105d45760203660031901126105d457600435611eda613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757611efe81613bd1565b60058110156111b45760048103611f225750634a5541ef60e01b5f5260045260245ffd5b60038103611f3d575063fe19f19f60e01b5f5260045260245ffd5b600214611ff957611f62815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57805f52600a60205260ff60405f205460f01c1615611fe7576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d45760203660031901126105d4576004356001600160a01b0381168091036105d4576001600160a01b035f54163381036120e6575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120d25760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d4576121156133b3565b5f546001600160a01b0381163381036120e657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d45760203660031901126105d4576001600160a01b0361218b6133b3565b1680156121a8575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d45760203660031901126105d45760206121f2600435613aa8565b6001600160a01b0360405191168152f35b346105d45760203660031901126105d45760043561221f6138b9565b50805f52600a60205260ff600160405f20015460a81c1615610647575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c16612269836134d7565b8252602082015261228f8251809264ffffffffff60208092828151168552015116910152565bf35b346105d45760403660031901126105d45760043567ffffffffffffffff81116105d4576122c290369060040161342d565b9060243567ffffffffffffffff81116105d4576122e390369060040161342d565b9190926122ee613d9f565b82810361261a575f5b81811061230057005b61230b818385613881565b35612317828486613881565b355f5260036020526001600160a01b0360405f2054169061234161233c84888a613881565b6138a5565b9161234a613d9f565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959578015612607576001600160801b0383169081156125f457825f5260036020526001600160a01b0360405f2054169384821415806125e4575b6125c9576001600160801b036123cc856145f7565b168084116125af57506123f190845f52600a602052600260405f20015460801c61461d565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561242b90613945565b6001600160801b0361244f81602084015116928260408183511692015116906135a0565b16111561257d575b825f52600a6020526001600160a01b03600160405f2001541661247b83838361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612567575b6124ec575b505050506001016122f7565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91612549575b501603610497578080806124e0565b612561915060203d81116104ea576104dc818361352c565b8961253a565b50835f52600960205260ff60405f2054166124db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612457565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506125ee846144d2565b156123b7565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a11602091614544565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f6126bd82613bd1565b60058110156111b4576002036126db575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126ce565b346105d4575f3660031901126105d45760206001600160a01b0360085416604051908152f35b346105d45760203660031901126105d457600435612737613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c16156128b457612776816144d2565b15611e2b57805f5260036020526001600160a01b0360405f2054161515806128ad575b80612890575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612847575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061283557005b637e27328960e01b5f5260045260245ffd5b612866835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f1981540190556127ed565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561279f565b505f612799565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4576111176128f0366133f3565b906040519261290060208561352c565b5f8452613998565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d45760203660031901126105d457600435612974613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c165f146129bd57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611e41576129ef815f52600a6020526001600160a01b0360405f205416331490565b15611e2b576129fd81613aea565b90805f52600a602052612a15600260405f2001613945565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081612a699481885116031695015116906135a0565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612beb575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b536001600160a01b03600160405f2001541694611cec88858861477b565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b9657005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f916108cf5750160361049757005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ab3565b346105d45760203660031901126105d457612c296133b3565b6001600160a01b035f541690338203612d6857806001600160a01b03913b15612d3c57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f1575f91612d0d575b5015612ce257805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d2f915060203d602011612d35575b612d27818361352c565b810190613869565b82612c97565b503d612d1d565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d45761014060031982360301126105d457612db9613d9f565b604051612dc5816134ba565b612dd1826004016133df565b8152612ddf602483016133df565b6020820152612df06044830161356a565b604082015260648201356001600160a01b03811681036105d4576060820152612e1b608483016134ad565b6080820152612e2c60a483016134ad565b60a0820152612e3d60c483016137da565b60c082015260e482013567ffffffffffffffff81116105d457820191366023840112156105d457600483013592612e73846137ec565b90612e81604051928361352c565b848252602060048184019660061b83010101903682116105d457602401945b818610612ec25760206116b5866116aa878760e084015261010436910161383a565b6020604091612ed13689613804565b815201950194612ea0565b346105d45760203660031901126105d4576001600160a01b03612efd6133b3565b165f526009602052602060ff60405f2054166040519015158152f35b346105d4575f3660031901126105d45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105d457611117612f64366133f3565b916135c0565b346105d4575f3660031901126105d4576020600754604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757612fbf90613bd1565b60058110156111b4578060209115908115612fe0575b506040519015158152f35b600191501482612fd5565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576020905f90805f52600a835260ff60405f205460f01c1680613080575b61304e575b506001600160801b0360405191168152f35b61307a9150805f52600a83526130746001600160801b03600260405f2001541691613aea565b906135a0565b8261303c565b50805f52600a835260ff600160405f20015460a01c1615613037565b346105d45760403660031901126105d4576130b56133b3565b6024356130c181613aa8565b3315158061318e575b8061315b575b61312f5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156130d0565b50336001600160a01b03821614156130ca565b346105d45760203660031901126105d45760206121f260043561357e565b346105d4575f3660031901126105d4576040515f6001548060011c90600181168015613270575b6020831081146113b757828552908115611393575060011461321257610b48836113218185038261352c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061325657509091508101602001611321611311565b91926001816020925483858801015201910190929161323e565b91607f16916131e6565b346105d4575f3660031901126105d457602060405167016345785d8a00008152f35b346105d45760203660031901126105d457600435906001600160e01b031982168092036105d457817f4906490600000000000000000000000000000000000000000000000000000000602093149081156132f8575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613343575b8115613332575b50836132f1565b6301ffc9a760e01b9150148361332b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613324565b5f5b83811061337e5750505f910152565b818101518382015260200161336f565b906020916133a78151809281855285808601910161336d565b601f01601f1916010190565b600435906001600160a01b03821682036105d457565b602435906001600160a01b03821682036105d457565b35906001600160a01b03821682036105d457565b60609060031901126105d4576004356001600160a01b03811681036105d457906024356001600160a01b03811681036105d4579060443590565b9181601f840112156105d45782359167ffffffffffffffff83116105d4576020808501948460051b0101116105d457565b90602080835192838152019201905f5b81811061347b5750505090565b825180516001600160801b0316855260209081015164ffffffffff16818601526040909401939092019160010161346e565b359081151582036105d457565b610120810190811067ffffffffffffffff821117611a9a57604052565b6040810190811067ffffffffffffffff821117611a9a57604052565b610180810190811067ffffffffffffffff821117611a9a57604052565b6060810190811067ffffffffffffffff821117611a9a57604052565b90601f8019910116810190811067ffffffffffffffff821117611a9a57604052565b67ffffffffffffffff8111611a9a57601f01601f191660200190565b35906001600160801b03821682036105d457565b61358781613aa8565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116120d257565b91906001600160a01b03168015610cbb57815f5260036020526001600160a01b0360405f2054161515806137d2575b806137b5575b6137a2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836136ed575b6001600160a01b039350856136b6575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8a57505050565b6136d5825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613655565b919290508061374b575b1561370457828291613645565b828461371c57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613779575b806136f75750825f526005602052336001600160a01b0360405f205416146136f7565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613756565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156135f5565b5060016135ef565b359064ffffffffff821682036105d457565b67ffffffffffffffff8111611a9a5760051b60200190565b91908260409103126105d45760405161381c816134d7565b602061383581839561382d8161356a565b8552016137da565b910152565b91908260409103126105d457604051613852816134d7565b6020808294613860816133df565b84520135910152565b908160209103126105d4575180151581036105d45790565b91908110156138915760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105d45790565b604051906138c6826134d7565b5f6020838281520152565b9081546138dd816137ec565b926138eb604051948561352c565b81845260208401905f5260205f205f915b8383106139095750505050565b60016020819260405161391b816134d7565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906138fc565b9060405161395281613510565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105d45790565b3580151581036105d45790565b906139a48382846135c0565b803b6139b1575b50505050565b6020916139f76001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061338e565b03815f865af15f9181613a67575b50613a335750613a136145c8565b80519081613a2e5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613a5557505f8080806139ab565b633250574960e11b5f5260045260245ffd5b613a8191925060203d6020116104ea576104dc818361352c565b905f613a05565b908160209103126105d457516001600160e01b0319811681036105d45790565b805f5260036020526001600160a01b0360405f205416908115612835575090565b8051156138915760200190565b80518210156138915760209160051b010190565b9064ffffffffff421691805f52600b602052613b0860405f206138d1565b908364ffffffffff6020613b1b85613ac9565b5101511611613bca57805f52600a6020528364ffffffffff60405f205460c81c161115613bab57506001600160801b03613b5482613ac9565b515116916001925b8251841015613ba4578464ffffffffff6020613b788787613ad6565b5101511611613ba4576001600160801b0360019181613b978787613ad6565b5151160116930192613b5c565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613bf35750600490565b805f52600a60205260405f205460f81c613c5f57805f52600a60205264ffffffffff60405f205460a01c164210613c5a57613c2d81613aea565b905f52600a6020526001600160801b0380600260405f200154169116105f14613c5557600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613d8d575b80613d70575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613d39575b1680613d21575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613cdd565b613d58835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613cd6565b50805f52600a60205260ff600160405f20015460b01c1615613c8a565b506001600160a01b0382161515613c84565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dd157565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613e1b6001600160801b03604084015116602061010085015101519061463d565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156144aa578015614482578151801561445a577f0000000000000000000000000000000000000000000000000000000000000000811161442f575064ffffffffff6020613e8984613ac9565b510151168110156143eb57505f905f905f81515f905b808210614363575050505064ffffffffff804216911690818110156143355750506001600160801b03169081810361430757505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406b8751975f19890190613ad6565b51015160c81b169360a01b169116171785555f5b818110614255575050600187016007556001600160a01b036020830151168015610cbb576140b5886001600160a01b0392613c65565b166142295786826141036001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061471a565b6001600160801b03602084015116806141f9575b506001600160a01b03815116946141ee6141d06001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141758b6134d7565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061345e565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614223906001600160a01b036060840151166001600160a01b03610100850151511690339061471a565b5f614117565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142708160e0870151613ad6565b5182549268010000000000000000841015611a9a5760018401808255841015613891576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161407f565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614387906001600160801b0361437e8588613ad6565b5151169061461d565b9364ffffffffff80602061439b8685613ad6565b510151169416808511156143b757506001849301909291613e9f565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff60206143fc84613ac9565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614518575b5081156144ff575090565b90506001600160a01b03614513339261357e565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6144f4565b805f52600a60205261455b600260405f2001613945565b90805f52600a60205260ff600160405f20015460a01c165f146145895750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6145ab57506145a890613aea565b90565b6145a891506001600160801b0360408183511692015116906135a0565b3d156145f2573d906145d98261354e565b916145e7604051938461352c565b82523d5f602084013e565b606090565b6145a89061460481614544565b905f52600a602052600260405f20015460801c906135a0565b906001600160801b03809116911601906001600160801b0382116120d257565b91909160405161464c816134d7565b5f81525f6020820152926001600160801b0382169081156146fd5767016345785d8a000081116146c6576146886001600160801b039183614850565b16602085019181835211156146b2576001600160801b0391826146ad925116906135a0565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161470e816134d7565b5f81525f602082015290565b9091926001600160a01b036147799481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261477460848361352c565b6147cb565b565b614779926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261477460648361352c565b5f806001600160a01b036147f493169360208151910182865af16147ed6145c8565b90836148fe565b8051908115159182614835575b505061480a5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148489250602080918301019101613869565b155f80614801565b9091905f19838209838202918280831092039180830392146148ed57670de0b6b3a76400008210156148bd577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061493b575080511561491357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614981575b61494c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561494456fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615e7e908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a6064610543818806615882565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615983565b60b76106ed5f615c76565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615c76565b98601b6028610a1a8c615d81565b610a2384615df9565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615c76565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615c76565b9660b7610ac189615d81565b610aca8b615df9565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615948565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615948565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615948565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615948565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bc7565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bc7565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c31565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c31565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b91615882565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615858575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161582d575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615802575b5083156157fa575b5082156157f2575b5081156157ea575b50156157e357600101615715565b5050505f90565b90505f6157d5565b91505f6157cd565b92505f6157c5565b7f7a00000000000000000000000000000000000000000000000000000000000000101592505f6157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b8061589657506040516156cc602082614713565b600a8110156158fc576158a890615408565b614824602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b81010301601f198101835282614713565b61590590615408565b614824602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526158eb81518092602086860191016146cd565b60405190615957604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615bb757615991615948565b9061271003906127108211614b1157602e60619160506159b361482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a40815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615ac782518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b28825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615bea88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c2082518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c5488945180928580880191016146cd565b830164010714051160dd1b83820152615c2082518093856025850191016146cd565b6004811015614dc75780615cc05750604051615c93604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d045750604051615cd7604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d4657604051615d19604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d54604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157e35790600d915f925f925b828410615da75750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615ddb88856156ff565b511614615df1575b820194600101929190615d94565b859450615de3565b5f90805180156157e357906010915f925f925b828410615e1f575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e5388856156ff565b511614615e69575b820194600101929190615e0c565b859450615e5b56fea164736f6c634300081a000a"; + hex"60808060405234601557615eaf908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a60646105438188066158b3565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906159b4565b60b76106ed5f615ca7565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615ca7565b98601b6028610a1a8c615db2565b610a2384615e2a565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615ca7565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615ca7565b9660b7610ac189615db2565b610aca8b615e2a565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615979565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615979565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615979565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615979565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bf8565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bf8565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c62565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c62565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b916158b3565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615889575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161585e575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615833575b8415615809575b508315615801575b5082156157f9575b5081156157f1575b50156157ea57600101615715565b5050505f90565b90505f6157dc565b91505f6157d4565b92505f6157cc565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6157c4565b7f7a0000000000000000000000000000000000000000000000000000000000000081111593506157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b806158c757506040516156cc602082614713565b600a81101561592d576158d990615408565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b81010301601f198101835282614713565b61593690615408565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b60405190615988604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615be8576159c2615979565b9061271003906127108211614b1157602e60619160506159e461482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a71815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615af882518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b59825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615c1b88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c5182518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c8588945180928580880191016146cd565b830164010714051160dd1b83820152615c5182518093856025850191016146cd565b6004811015614dc75780615cf15750604051615cc4604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d355750604051615d08604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d7757604051615d4a604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d85604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157ea5790600d915f925f925b828410615dd85750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e0c88856156ff565b511614615e22575b820194600101929190615dc5565b859450615e14565b5f90805180156157ea57906010915f925f925b828410615e50575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e8488856156ff565b511614615e9a575b820194600101929190615e3d565b859450615e8c56fea164736f6c634300081a000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol index a88661cc6..171dc4878 100644 --- a/src/SablierV2NFTDescriptor.sol +++ b/src/SablierV2NFTDescriptor.sol @@ -320,9 +320,9 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { return string.concat("Sablier V2 ", sablierModel, " #", streamId); } - /// @notice Checks whether the provided string contains only alphanumeric characters and spaces. + /// @notice Checks whether the provided string contains only alphanumeric characters, spaces, and dashes. /// @dev Note that this returns true for empty strings. - function isAlphanumericWithSpaces(string memory str) internal pure returns (bool) { + function isAllowedCharacter(string memory str) internal pure returns (bool) { // Convert the string to bytes to iterate over its characters. bytes memory b = bytes(str); @@ -330,12 +330,13 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { for (uint256 i = 0; i < length; ++i) { bytes1 char = b[i]; - // Check if it's a space or an alphanumeric character. + // Check if it's a space, dash, or an alphanumeric character. bool isSpace = char == 0x20; // space + bool isDash = char == 0x2D; // dash bool isDigit = char >= 0x30 && char <= 0x39; // 0-9 bool isUppercaseLetter = char >= 0x41 && char <= 0x5A; // A-Z bool isLowercaseLetter = char >= 0x61 && char <= 0x7A; // a-z - if (!(isSpace || isDigit || isUppercaseLetter || isLowercaseLetter)) { + if (!(isSpace || isDash || isDigit || isUppercaseLetter || isLowercaseLetter)) { return false; } } @@ -381,12 +382,12 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { string memory symbol = abi.decode(returnData, (string)); - // Check if the symbol is too long or contains non-alphanumeric characters, this measure helps mitigate - // potential security threats from malicious assets injecting scripts in the symbol string. + // Check if the symbol is too long or contains disallowed characters. This measure helps mitigate potential + // security threats from malicious assets injecting scripts in the symbol string. if (bytes(symbol).length > 30) { return "Long Symbol"; } else { - if (!isAlphanumericWithSpaces(symbol)) { + if (!isAllowedCharacter(symbol)) { return "Unsupported Symbol"; } return symbol; diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 7701a85c1..a192fc8d2 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -24,7 +24,7 @@ interface ISablierV2Lockup is /// @notice Emitted when the admin allows a new recipient contract to hook to Sablier. /// @param admin The address of the current contract admin. /// @param recipient The address of the recipient contract put on the allowlist. - event AllowToHook(address admin, address recipient); + event AllowToHook(address indexed admin, address recipient); /// @notice Emitted when a stream is canceled. /// @param streamId The ID of the stream. diff --git a/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol b/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol new file mode 100644 index 000000000..95c4ea4a8 --- /dev/null +++ b/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; + +contract IsAllowedCharacter_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { + function test_IsAllowedCharacter_EmptyString() external view { + string memory symbol = ""; + bool result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + } + + modifier whenNotEmptyString() { + _; + } + + function test_IsAllowedCharacter_ContainsUnsupportedCharacters() external view whenNotEmptyString { + string memory symbol = ""; + bool result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo/"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo\\"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo%"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo&"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo("; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo)"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo\""; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo'"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo`"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo;"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + + symbol = "foo%20"; // URL-encoded empty space + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertFalse(result, "isAllowedCharacter"); + } + + modifier whenOnlySupportedCharacters() { + _; + } + + function test_IsAllowedCharacter() external view whenNotEmptyString whenOnlySupportedCharacters { + string memory symbol = "foo"; + bool result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "Foo"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "Foo "; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "Foo Bar"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "Bar-Foo"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = " "; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "foo01234"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + + symbol = "123456789"; + result = nftDescriptorMock.isAllowedCharacter_(symbol); + assertTrue(result, "isAllowedCharacter"); + } +} diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree b/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree similarity index 91% rename from test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree rename to test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree index 4583ea755..924004a0a 100644 --- a/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.tree +++ b/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree @@ -1,4 +1,4 @@ -isAlphanumericWithSpaces.t.sol +isAllowedCharacter.t.sol ├── when the symbol is an empty string │ └── it should return true └── when the symbol is not an empty string diff --git a/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol b/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol deleted file mode 100644 index 59fa92a11..000000000 --- a/test/integration/concrete/nft-descriptor/is-alphanumeric-with-spaces/isAlphanumericWithSpaces.t.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; - -contract IsAlphanumericWithSpaces_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { - function test_IsAlphanumericWithSpaces_EmptyString() external view { - string memory symbol = ""; - bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - } - - modifier whenNotEmptyString() { - _; - } - - function test_IsAlphanumericWithSpaces_ContainsUnsupportedCharacters() external view whenNotEmptyString { - string memory symbol = ""; - bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo/"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo\\"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo%"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo&"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo("; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo)"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo\""; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo'"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo`"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo;"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - - symbol = "foo%20"; // URL-encoded empty space - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertFalse(result, "isAlphanumericWithSpaces"); - } - - modifier whenOnlySupportedCharacters() { - _; - } - - function test_IsAlphanumericWithSpaces() external view whenNotEmptyString whenOnlySupportedCharacters { - string memory symbol = "foo"; - bool result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = "Foo"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = "Foo "; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = "Foo Bar"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = " "; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = "foo01234"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - - symbol = "123456789"; - result = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertTrue(result, "isAlphanumericWithSpaces"); - } -} diff --git a/test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol b/test/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol similarity index 74% rename from test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol rename to test/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol index 4d5df33df..1976e23b9 100644 --- a/test/integration/fuzz/nft-descriptor/isAlphanumericWithSpaces.t.sol +++ b/test/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol @@ -3,8 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract IsAlphanumericWithSpaces_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { +contract IsAllowedCharacter_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { bytes1 internal constant SPACE = 0x20; // ASCII 32 + bytes1 internal constant DASH = 0x2D; // ASCII 45 bytes1 internal constant ZERO = 0x30; // ASCII 48 bytes1 internal constant NINE = 0x39; // ASCII 57 bytes1 internal constant A = 0x41; // ASCII 65 @@ -21,7 +22,7 @@ contract IsAlphanumericWithSpaces_Integration_Fuzz_Test is NFTDescriptor_Integra /// - String with only alphanumerical characters /// - String with only non-alphanumerical characters /// - String with both alphanumerical and non-alphanumerical characters - function testFuzz_IsAlphanumericWithSpaces(string memory symbol) external view whenNotEmptyString { + function testFuzz_IsAllowedCharacter(string memory symbol) external view whenNotEmptyString { bytes memory b = bytes(symbol); uint256 length = b.length; bool expectedResult = true; @@ -32,15 +33,16 @@ contract IsAlphanumericWithSpaces_Integration_Fuzz_Test is NFTDescriptor_Integra break; } } - bool actualResult = nftDescriptorMock.isAlphanumericWithSpaces_(symbol); - assertEq(actualResult, expectedResult, "isAlphanumericWithSpaces"); + bool actualResult = nftDescriptorMock.isAllowedCharacter_(symbol); + assertEq(actualResult, expectedResult, "isAllowedCharacter"); } function isAlphanumericOrSpaceChar(bytes1 char) internal pure returns (bool) { bool isSpace = char == SPACE; + bool isDash = char == DASH; bool isDigit = char >= ZERO && char <= NINE; bool isUppercaseLetter = char >= A && char <= Z; bool isLowercaseLetter = char >= a && char <= z; - return isSpace || isDigit || isUppercaseLetter || isLowercaseLetter; + return isSpace || isDash || isDigit || isUppercaseLetter || isLowercaseLetter; } } diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index f63eca0cf..f0315e156 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -78,8 +78,8 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { return SVGElements.hourglass(status); } - function isAlphanumericWithSpaces_(string memory symbol) external pure returns (bool) { - return isAlphanumericWithSpaces(symbol); + function isAllowedCharacter_(string memory symbol) external pure returns (bool) { + return isAllowedCharacter(symbol); } function mapSymbol_(IERC721Metadata nft) external view returns (string memory) { diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 21e959781..05fa6890c 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -32,7 +32,7 @@ abstract contract Events { SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ - event AllowToHook(address admin, address recipient); + event AllowToHook(address indexed admin, address recipient); event CancelLockupStream( uint256 streamId, From 36b49d3bf2a396d19083d28247e8e03d7a3a2ee1 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:01:54 +0300 Subject: [PATCH 128/132] refactor: return the withdrawable amount in withdrawMax and withdrawMaxAndTransfer (#961) * refactor: return the withdrawn amount test: the return value in withdrawMax and withdrawMaxAndTransfer * chore: update precompiles * shub feedback --- precompiles/Precompiles.sol | 6 +++--- src/abstracts/SablierV2Lockup.sol | 12 +++++++----- src/interfaces/ISablierV2Lockup.sol | 11 +++++++++-- .../withdrawMaxAndTransfer.t.sol | 11 +++++------ .../withdrawMaxAndTransfer.tree | 3 ++- .../lockup/withdraw-max/withdrawMax.t.sol | 16 +++++++--------- .../lockup/withdraw-max/withdrawMax.tree | 6 ++++-- 7 files changed, 37 insertions(+), 28 deletions(-) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index a63fc535f..a2fea12b5 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -26,11 +26,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e457615a3f6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615631908161040e823960805181613924015260a051818181610bbf01526139ee0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127bb57508063027b67441461279957806306fdde03146126de578063081812fc146126c0578063095ea7b3146125bb5780631400ecec1461250a5780631c1cdd4c146124a65780631e99d5691461248957806323b872dd14612472578063303acc851461243557806331df3d4814612322578063406887cb146121b357806340e58ee514611e9a578063425d30dd14611e4a57806342842e0e14611e2157806342966c6814611c5d5780634426757014611c375780634857501f14611bc65780634869e12d14611b8c5780634cc55e1114611a9457806354c02292146117e357806357404b12146117555780636352211e146117265780636d0cee751461172657806370a08231146116bc57806375829def1461164e5780637cad6cd11461155d5780637de6b1db146113de5780638659c27014610fe0578063894e9a0d14610cb15780638f69b99314610c315780639067b67714610be25780639188ec8414610ba857806395d89b4114610aa0578063a22cb465146109ec578063a80fc0711461099b578063ad35efd41461093c578063b2564569146108ec578063b637b86514610893578063b88d4fde1461080b578063b8a3be66146107d6578063b971302a14610788578063bc2be1be14610739578063c156a11d14610609578063c87b56dd146104f3578063d4dbd20b146104a2578063d511609f14610457578063d975dfed1461040c578063e985e9c5146103b3578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128e8565b6044356001600160801b03811681036102b0576102ae916102a661391a565b6004356133ce565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b0576102ae6004356103a46128e8565b6103ad826141f5565b9161305f565b346102b05760403660031901126102b0576103cc6128d2565b6001600160a01b036103dc6128e8565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576104466020916141f5565b6001600160801b0360405191168152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b0576004356105108161369c565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156105fe575f90610581575b61057d906040519182916020835260208301906128ad565b0390f35b503d805f833e6105918183612a6b565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105c983612a8d565b916105d76040519384612a6b565b838352602084830101116102b05761057d926105f9916020808501910161288c565b610565565b6040513d5f823e3d90fd5b346102b05760403660031901126102b0576004356106256128e8565b9061062e61391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f5260036020526001600160a01b0360405f2054169182330361071957610670826141f5565b6001600160801b038116610708575b506001600160a01b038116156106f5576106a1826001600160a01b03926137e0565b1691826106bb5750637e27328960e01b5f5260045260245ffd5b8083036106c457005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61071390848461305f565b8361067f565b5063216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108246128d2565b61082c6128e8565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161085983612a8d565b926108676040519485612a6b565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f6f565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b60205261057d6108d860405f20612ee8565b60405191829160208352602083019061297d565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576109749061374c565b6040516005821015610987576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a056128d2565b602435908115158092036102b0576001600160a01b0316908115610a7457335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610b9e575b602083108114610b8a57828552908115610b665750600114610b08575b61057d83610af481850382612a6b565b6040519182916020835260208301906128ad565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b4c57509091508101602001610af4610ae4565b919260018160209254838588010152019101909291610b34565b60ff191660208086019190915291151560051b84019091019150610af49050610ae4565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ac7565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c699061374c565b6005811015806109875760028214908115610ca5575b8115610c93575b6020826040519015158152f35b90506109875760046020911482610c86565b5050600381145f610c7f565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fcc57606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d2c612e98565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d6781612a4e565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e06600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612eb6565b61012083019081526002610e198c61374c565b610e22816129ef565b14610fc4575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610e996101808d612a6b565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610eed90612ee8565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161057d9161297d565b5f8752610e28565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101190369060040161294c565b9061101a61391a565b5f915b80831061102657005b611031838284612e27565b359261103b61391a565b835f52600a60205260ff600160405f20015460a81c16156113cb57835f52600a60205260ff600160405f20015460a01c165f146110855783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113b9576110ba815f52600a6020526001600160a01b0360405f205416331490565b156113a3576110c8816136bd565b90805f52600a6020526110e0600260405f2001612eb6565b916001600160801b038351166001600160801b038216101561138f57815f52600a60205260ff60405f205460f01c161561137b57806001600160801b03602081611134948188511603169501511690612adf565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611356575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061124f6001600160a01b03600160405f200154169461122788858861464f565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff611299866001600160a01b03165f52600960205260405f2090565b54166112af575b5050505050600101919061101d565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91611328575b50160361130c57808080806112a0565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611349915060203d811161134f575b6113418183612a6b565b81019061367c565b876112fc565b503d611337565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561117e565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b0576004356113fa61391a565b805f52600a60205260ff600160405f20015460a81c16156103235761141e8161374c565b611427816129ef565b600481036114425750634a5541ef60e01b5f5260045260245ffd5b61144b816129ef565b60038103611466575063fe19f19f60e01b5f5260045260245ffd5b600290611472816129ef565b1461154b57611495815f52600a6020526001600160a01b0360405f205416331490565b1561152c57805f52600a60205260ff60405f205460f01c161561151a576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611638575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116245760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116676128d2565b5f546001600160a01b03811633810361163857506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116dd6128d2565b1680156116fa575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174460043561369c565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b057600435611771612e80565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117bb83612a32565b825260208201526117e18251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761181e61391a565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b057611860913691612d43565b9081519161186d83612d2b565b9261187b6040519485612a6b565b808452601f1961188a82612d2b565b015f5b818110611a7d57505064ffffffffff4216916001600160801b036118b082613974565b51511667ffffffffffffffff60206118c784613974565b5101511664ffffffffff8060406118dd86613974565b5101511686011690604051926118f284612a16565b83526020830152604082015261190786613974565b5261191185613974565b5060015b8281106119e95750505061192b82600401612e5f565b9261193860248401612e5f565b9261194560448201612e4b565b916064820135936001600160a01b0385168095036102b0576020966119e1966119a1966001600160801b036119d6976001600160a01b0361198860848a01612e73565b948161199660a48c01612e73565b976040519d8e6129f9565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612de0565b610100820152613995565b604051908152f35b806001600160801b036119fe60019385613981565b51511667ffffffffffffffff6020611a168487613981565b5101511664ffffffffff806040611a305f1987018d613981565b51015116816040611a41878a613981565b5101511601169060405192611a5584612a16565b835260208301526040820152611a6b8289613981565b52611a768188613981565b5001611915565b602090611a88612e98565b8282890101520161188d565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ac590369060040161294c565b9060243567ffffffffffffffff81116102b057611ae690369060040161294c565b9091611af061391a565b818403611b5c575f5b848110611b0257005b80611b56611b136001938886612e27565b35611b1f838987612e27565b355f5260036020526001600160a01b0360405f205416611b48611b4385898b612e27565b612e4b565b91611b5161391a565b6133ce565b01611af9565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610446602091614145565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611bff8261374c565b600581101561098757600203611c1d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c10565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c7961391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611df657611cb8816140d3565b156113a357805f5260036020526001600160a01b0360405f205416151580611def575b80611dd2575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d89575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d7757005b637e27328960e01b5f5260045260245ffd5b611da8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d2f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611ce1565b505f611cdb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3236612912565b9060405192611e42602085612a6b565b5f8452612f6f565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611eb661391a565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611eff57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113b957611f31815f52600a6020526001600160a01b0360405f205416331490565b1561152c57611f3f816136bd565b90805f52600a602052611f57600260405f2001612eb6565b916001600160801b038351166001600160801b03821610156121a057815f52600a60205260ff60405f205460f01c161561218d57806001600160801b03602081611fab948188511603169501511690612adf565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612168575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061209e6001600160a01b03600160405f200154169461122788858861464f565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120e157005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156105fe57630d4af11f60e31b916001600160e01b0319915f91612149575b50160361213757005b632187e5e760e21b5f5260045260245ffd5b612162915060203d60201161134f576113418183612a6b565b8461212e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611ff5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121cc6128d2565b6001600160a01b035f54169033820361230b57806001600160a01b03913b156122df57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156105fe575f916122b0575b501561228557805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122d2915060203d6020116122d8575b6122ca8183612a6b565b810190612e0f565b8261223a565b503d6122c0565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761235c61391a565b60405190612369826129f9565b612375816004016128fe565b8252612383602482016128fe565b602083015261239460448201612aa9565b604083015260648101356001600160a01b03811681036102b05760608301526123bf608482016129e2565b60808301526123d060a482016129e2565b60a08301526123e160c48201612d19565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119d66119e1926124256020953690602460048201359101612d43565b60e0840152610104369101612de0565b346102b05760203660031901126102b0576001600160a01b036124566128d2565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248336612912565b91612aff565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124de9061374c565b60058110156109875780602091159081156124ff575b506040519015158152f35b6001915014826124f4565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c168061259f575b61256d575b506001600160801b0360405191168152f35b6125999150805f52600a83526125936001600160801b03600260405f20015416916136bd565b90612adf565b8261255b565b50805f52600a835260ff600160405f20015460a01c1615612556565b346102b05760403660031901126102b0576125d46128d2565b6024356125e08161369c565b331515806126ad575b8061267a575b61264e5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125ef565b50336001600160a01b03821614156125e9565b346102b05760203660031901126102b0576020611744600435612abd565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561278f575b602083108114610b8a57828552908115610b6657506001146127315761057d83610af481850382612a6b565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061277557509091508101602001610af4610ae4565b91926001816020925483858801015201910190929161275d565b91607f1691612705565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612817575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612862575b8115612851575b5083612810565b6301ffc9a760e01b9150148361284a565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612843565b5f5b83811061289d5750505f910152565b818101518382015260200161288e565b906020916128c68151809281855285808601910161288c565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b81811061299a5750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161298d565b359081151582036102b057565b6005111561098757565b610120810190811067ffffffffffffffff821117610fcc57604052565b6060810190811067ffffffffffffffff821117610fcc57604052565b6040810190811067ffffffffffffffff821117610fcc57604052565b610140810190811067ffffffffffffffff821117610fcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610fcc57604052565b67ffffffffffffffff8111610fcc57601f01601f191660200190565b35906001600160801b03821682036102b057565b612ac68161369c565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162457565b91906001600160a01b031680156106f557815f5260036020526001600160a01b0360405f205416151580612d11575b80612cf4575b612ce1577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c2c575b6001600160a01b03935085612bf5575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4168083036106c457505050565b612c14825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b94565b9192905080612c8a575b15612c4357828291612b84565b8284612c5b57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cb8575b80612c365750825f526005602052336001600160a01b0360405f20541614612c36565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c95565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b34565b506001612b2e565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fcc5760051b60200190565b929192612d4f82612d2b565b93612d5d6040519586612a6b565b60606020868581520193028201918183116102b057925b828410612d815750505050565b6060848303126102b05760405190612d9882612a16565b612da185612aa9565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612dd060408801612d19565b6040820152815201930192612d74565b91908260409103126102b057604051612df881612a32565b6020808294612e06816128fe565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e375760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612e8d82612a32565b5f6020838281520152565b60405190612ea582612a16565b5f6040838281528260208201520152565b90604051612ec381612a16565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612ef481612d2b565b92612f026040519485612a6b565b81845260208401905f5260205f205f915b838310612f205750505050565b600160208192604051612f3281612a16565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f13565b90612f7b838284612aff565b803b612f88575b50505050565b602091612fce6001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128ad565b03815f865af15f918161303e575b5061300a5750612fea6141c6565b805190816130055782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361302c57505f808080612f82565b633250574960e11b5f5260045260245ffd5b61305891925060203d60201161134f576113418183612a6b565b905f612fdc565b9061306861391a565b815f52600a60205260ff600160405f20015460a81c16156133bc57815f52600a60205260ff600160405f20015460a01c166133a9576001600160a01b038116801561337d576001600160801b03841691821561335157835f5260036020526001600160a01b0360405f205416948583141580613341575b61330d576001600160801b036130f4866141f5565b168085116132da575061311990855f52600a602052600260405f20015460801c61421b565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561315c90612eb6565b6001600160801b036131808160208401511692826040818351169201511690612adf565b1611156132a8575b835f52600a6020526131ac836001600160a01b03600160405f20015416928361464f565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613292575b6132165750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f91613273575b50160361213757808080612f82565b61328c915060203d60201161134f576113418183612a6b565b5f613264565b50835f52600960205260ff60405f20541661320c565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613188565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061334b856140d3565b156130df565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c16156133bc57815f52600a60205260ff600160405f20015460a01c166133a9576001600160a01b038116801561337d576001600160801b03841691821561335157835f5260036020526001600160a01b0360405f20541694858314158061366c575b61330d576001600160801b0361345b866141f5565b168085116132da575061348090855f52600a602052600260405f20015460801c61421b565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134c390612eb6565b6001600160801b036134e78160208401511692826040818351169201511690612adf565b16111561363a575b835f52600a602052613513836001600160a01b03600160405f20015416928361464f565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613615575b61357d5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156105fe576392b9102b60e01b916001600160e01b0319915f916135f6575b5016036135da57808080612f82565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b61360f915060203d60201161134f576113418183612a6b565b5f6135cb565b5060ff613633856001600160a01b03165f52600960205260405f2090565b5416613573565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556134ef565b50613676856140d3565b15613446565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d77575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561374657815f52600a60205264ffffffffff60405f205460c81c16111561372b57805f52600b602052600160405f2054115f146137225761371f906142fb565b90565b61371f9061423b565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f1461376e5750600490565b805f52600a60205260405f205460f81c6137da57805f52600a60205264ffffffffff60405f205460a01c1642106137d5576137a8816136bd565b905f52600a6020526001600160801b0380600260405f200154169116105f146137d057600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613908575b806138eb575b611dc0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138b4575b168061389c575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613858565b6138d3835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613851565b50805f52600a60205260ff600160405f20015460b01c1615613805565b506001600160a01b03821615156137ff565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361394c57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e375760200190565b8051821015612e375760209160051b010190565b906139b76001600160801b036040840151166020610100850151015190614511565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140ab578015614083578151801561405b577f00000000000000000000000000000000000000000000000000000000000000008111614030575064ffffffffff6040613a2584613974565b51015116811015613fec57505f905f905f81515f905b808210613f64575050505064ffffffffff80421691169081811015613f365750506001600160801b031690818103613f0857505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c108751975f19890190613981565b51015160c81b169360a01b169116171785555f5b818110613dfa575050600187016007556001600160a01b0360208301511680156106f557613c5a886001600160a01b03926137e0565b16613dce578682613ca86001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145ee565b6001600160801b0360208401511680613d9e575b506001600160a01b0381511694613d93613d756001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d1a8b612a32565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061297d565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dc8906001600160a01b036060840151166001600160a01b0361010085015151169033906145ee565b5f613cbc565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e158160e0870151613981565b51825468010000000000000000811015610fcc5760018101808555811015612e37576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c24565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f88906001600160801b03613f7f8588613981565b5151169061421b565b9364ffffffffff806040613f9c8685613981565b51015116941680851115613fb857506001849301909291613a3b565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff6040613ffd84613974565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614119575b508115614100575090565b90506001600160a01b036141143392612abd565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6140f5565b805f52600a60205261415c600260405f2001612eb6565b90805f52600a60205260ff600160405f20015460a01c165f1461418a5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141a9575061371f906136bd565b61371f91506001600160801b036040818351169201511690612adf565b3d156141f0573d906141d782612a8d565b916141e56040519384612a6b565b82523d5f602084013e565b606090565b61371f9061420281614145565b905f52600a602052600260405f20015460801c90612adf565b906001600160801b03809116911601906001600160801b03821161162457565b5f818152600a60205260409020546142729064ffffffffff60a082901c811660c89290921c8116829003811691428216031661469f565b90805f52600b60205260405f20805415612e37575f526142c767ffffffffffffffff60205f205460801c1692825f52600a6020526142c26001600160801b03600260405f2001541694859261477f565b6147f2565b9182136142e457506142e06001600160801b03916148cd565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061431f82612a4e565b6101206143b260028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612eb6565b92019182525f52600b6020526143ca60405f20612ee8565b915f9264ffffffffff60406143de83613974565b510151168664ffffffffff5f925b16106144d2578161446364ffffffffff9697988784816001600160801b0361441b6142c2986144689b9a613981565b5151169a8b9867ffffffffffffffff6020614436868b613981565b51015116978260406144488784613981565b5101511694806144b5575050511680925b031692031661469f565b61477f565b9182136144895750906001600160801b0361448381936148cd565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144b0575090565b905090565b60409250906144c7915f190190613981565b510151168092614459565b936001600160801b03600191816144e98886613981565b51511601169401958064ffffffffff8060406145058b87613981565b510151169892986143ec565b91909160405161452081612a32565b5f81525f6020820152926001600160801b0382169081156145d15767016345785d8a0000811161459a5761455c6001600160801b0391836154ea565b1660208501918183521115614586576001600160801b03918261458192511690612adf565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145e281612a32565b5f81525f602082015290565b9091926001600160a01b0361464d9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614648608483612a6b565b614902565b565b61464d926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614648606483612a6b565b600160ff1b81148015614772575b61474a575f811215614741576146d1815f035b5f84121561473a57835f0390614987565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161470b575f19911813156147065790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614987565b6146d1816146c0565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146ad565b80614799575061479557670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147e457806147bc575050670de0b6b3a764000090565b670de0b6b3a764000081146147e0576147db906142c261371f93614a8d565b614be4565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148c0575b614898575f81121561488f57614824815f035b5f84121561488857835f03906154ea565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311614859575f19911813156147065790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154ea565b61482481614813565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614800565b5f81126148d75790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361492b93169360208151910182865af16149246141c6565b9083615598565b805190811515918261496c575b50506149415750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61497f9250602080918301019101612e0f565b155f80614938565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a525781841015614a1857670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a5f570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a5f576ec097ce7bc90715b34b9f10000000000590565b805f811315614bb957670de0b6b3a76400008112614b9957506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b8657506706f05b59d3b20000905b5f8213614b505750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b78575b60011d90614b43565b809192019160011d90614b6f565b9050670de0b6b3a7640000929150020290565b5f1991508015614a5f576ec097ce7bc90715b34b9f100000000005614aaa565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c115768033dd1780914b971141981126137d557614c08905f03614be4565b61371f90614a73565b680a688906bd8affffff81136154bf57670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661538a575b670de0b6b3a76400009066ff000000000000831661527a575b65ff00000000008316615172575b64ff000000008316615072575b63ff0000008316614f7a575b62ff00008316614e8a575b61ff008316614da2575b60ff8316614cc2575b029060401c60bf031c90565b60808316614d8f575b60408316614d7c575b60208316614d69575b60108316614d56575b60088316614d43575b60048316614d30575b60028316614d1d575b6001831615614cb657680100000000000000010260401c614cb6565b680100000000000000010260401c614d01565b680100000000000000030260401c614cf8565b680100000000000000060260401c614cef565b6801000000000000000b0260401c614ce6565b680100000000000000160260401c614cdd565b6801000000000000002c0260401c614cd4565b680100000000000000590260401c614ccb565b6180008316614e77575b6140008316614e64575b6120008316614e51575b6110008316614e3e575b6108008316614e2b575b6104008316614e18575b6102008316614e05575b610100831615614cad57680100000000000000b10260401c614cad565b680100000000000001630260401c614de8565b680100000000000002c60260401c614dde565b6801000000000000058c0260401c614dd4565b68010000000000000b170260401c614dca565b6801000000000000162e0260401c614dc0565b68010000000000002c5d0260401c614db6565b680100000000000058b90260401c614dac565b628000008316614f67575b624000008316614f54575b622000008316614f41575b621000008316614f2e575b620800008316614f1b575b620400008316614f08575b620200008316614ef5575b62010000831615614ca3576801000000000000b1720260401c614ca3565b680100000000000162e40260401c614ed7565b6801000000000002c5c80260401c614ecc565b68010000000000058b910260401c614ec1565b680100000000000b17210260401c614eb6565b68010000000000162e430260401c614eab565b680100000000002c5c860260401c614ea0565b6801000000000058b90c0260401c614e95565b6380000000831661505f575b6340000000831661504c575b63200000008316615039575b63100000008316615026575b63080000008316615013575b63040000008316615000575b63020000008316614fed575b6301000000831615614c985768010000000000b172180260401c614c98565b6801000000000162e4300260401c614fce565b68010000000002c5c8600260401c614fc2565b680100000000058b90c00260401c614fb6565b6801000000000b17217f0260401c614faa565b680100000000162e42ff0260401c614f9e565b6801000000002c5c85fe0260401c614f92565b68010000000058b90bfc0260401c614f86565b648000000000831661515f575b644000000000831661514c575b6420000000008316615139575b6410000000008316615126575b6408000000008316615113575b6404000000008316615100575b64020000000083166150ed575b640100000000831615614c8c57680100000000b17217f80260401c614c8c565b68010000000162e42ff10260401c6150cd565b680100000002c5c85fe30260401c6150c0565b6801000000058b90bfce0260401c6150b3565b68010000000b17217fbb0260401c6150a6565b6801000000162e42fff00260401c615099565b68010000002c5c8601cc0260401c61508c565b680100000058b90c0b490260401c61507f565b658000000000008316615267575b654000000000008316615254575b652000000000008316615241575b65100000000000831661522e575b65080000000000831661521b575b650400000000008316615208575b6502000000000083166151f5575b65010000000000831615614c7f576801000000b1721835510260401c614c7f565b680100000162e430e5a20260401c6151d4565b6801000002c5c863b73f0260401c6151c6565b68010000058b90cf1e6e0260401c6151b8565b680100000b1721bcfc9a0260401c6151aa565b68010000162e43f4f8310260401c61519c565b680100002c5c89d5ec6d0260401c61518e565b6801000058b91b5bc9ae0260401c615180565b66800000000000008316615377575b66400000000000008316615364575b66200000000000008316615351575b6610000000000000831661533e575b6608000000000000831661532b575b66040000000000008316615318575b66020000000000008316615305575b6601000000000000831615614c715768010000b17255775c040260401c614c71565b6801000162e525ee05470260401c6152e3565b68010002c5cc37da94920260401c6152d4565b680100058ba01fb9f96d0260401c6152c5565b6801000b175effdc76ba0260401c6152b6565b680100162f3904051fa10260401c6152a7565b6801002c605e2e8cec500260401c615298565b68010058c86da1c09ea20260401c615289565b67800000000000000082166154a0575b670de0b6b3a764000090674000000000000000831661548d575b672000000000000000831661547a575b6710000000000000008316615467575b6708000000000000008316615454575b6704000000000000008316615441575b670200000000000000831661542e575b670100000000000000831661541b575b9050614c58565b680100b1afa5abcbed610260401c615414565b68010163da9fb33356d80260401c615404565b680102c9a3e778060ee70260401c6153f4565b6801059b0d31585743ae0260401c6153e4565b68010b5586cf9890f62a0260401c6153d4565b6801172b83c7d517adce0260401c6153c4565b6801306fe0a31b7152df0260401c6153b4565b5077b504f333f9de64848000000000000000000000000000000061539a565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461558757670de0b6b3a7640000821015615557577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155d557508051156155ad57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061561b575b6155e6575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155de56fea164736f6c634300081a000a"; + hex"60c0604052346103e457615a506060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615642908161040e823960805181613935015260a051818181610bca01526139ff0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c657508063027b6744146127a457806306fdde03146126e9578063081812fc146126cb578063095ea7b3146125c65780631400ecec146125155780631c1cdd4c146124b15780631e99d5691461249457806323b872dd1461247d578063303acc851461244057806331df3d481461232d578063406887cb146121be57806340e58ee514611ea5578063425d30dd14611e5557806342842e0e14611e2c57806342966c6814611c685780634426757014611c425780634857501f14611bd15780634869e12d14611b975780634cc55e1114611a9f57806354c02292146117ee57806357404b12146117605780636352211e146117315780636d0cee751461173157806370a08231146116c757806375829def146116595780637cad6cd1146115685780637de6b1db146113e95780638659c27014610feb578063894e9a0d14610cbc5780638f69b99314610c3c5780639067b67714610bed5780639188ec8414610bb357806395d89b4114610aab578063a22cb465146109f7578063a80fc071146109a6578063ad35efd414610947578063b2564569146108f7578063b637b8651461089e578063b88d4fde14610816578063b8a3be66146107e1578063b971302a14610793578063bc2be1be14610744578063c156a11d1461060e578063c87b56dd146104f8578063d4dbd20b146104a7578063d511609f1461045c578063d975dfed14610422578063e985e9c5146103c9578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f3565b6044356001600160801b03811681036102b0576102ae916102a661392b565b6004356133df565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b86103a66128f3565b916103b081614206565b928391613082565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e26128dd565b6001600160a01b036103f26128f3565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614206565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610515816136ad565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610603575f90610586575b610582906040519182916020835260208301906128b8565b0390f35b503d805f833e6105968183612a76565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105ce83612a98565b916105dc6040519384612a76565b838352602084830101116102b057610582926105fe9160208085019101612897565b61056a565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062a6128f3565b61063261392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f5260036020526001600160a01b0360405f205416908133036107125761067483614206565b6001600160801b0381169182610702575b6001600160a01b038116156106ef576106a6856001600160a01b03926137f1565b1692836106c05784637e27328960e01b5f5260045260245ffd5b80859185036106d457602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070d828587613082565b610685565b8263216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b05761082f6128dd565b6108376128f3565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086483612a98565b926108726040519485612a76565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105826108e360405f20612f0b565b604051918291602083526020830190612988565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761097f9061375d565b6040516005821015610992576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a106128dd565b602435908115158092036102b0576001600160a01b0316908115610a7f57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610ba9575b602083108114610b9557828552908115610b715750600114610b13575b61058283610aff81850382612a76565b6040519182916020835260208301906128b8565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5757509091508101602001610aff610aef565b919260018160209254838588010152019101909291610b3f565b60ff191660208086019190915291151560051b84019091019150610aff9050610aef565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad2565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c749061375d565b6005811015806109925760028214908115610cb0575b8115610c9e575b6020826040519015158152f35b90506109925760046020911482610c91565b5050600381145f610c8a565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd757606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d37612ebb565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7281612a59565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e11600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612ed9565b61012083019081526002610e248c61375d565b610e2d816129fa565b14610fcf575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea46101808d612a76565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610ef890612f0b565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161058291612988565b5f8752610e33565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101c903690600401612957565b9061102561392b565b5f915b80831061103157005b61103c838284612e4a565b359261104661392b565b835f52600a60205260ff600160405f20015460a81c16156113d657835f52600a60205260ff600160405f20015460a01c165f146110905783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c4576110c5815f52600a6020526001600160a01b0360405f205416331490565b156113ae576110d3816136ce565b90805f52600a6020526110eb600260405f2001612ed9565b916001600160801b038351166001600160801b038216101561139a57815f52600a60205260ff60405f205460f01c161561138657806001600160801b0360208161113f948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611361575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125a6001600160a01b03600160405f2001541694611232888588614660565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a4866001600160a01b03165f52600960205260405f2090565b54166112ba575b50505050506001019190611028565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91611333575b50160361131757808080806112ab565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611354915060203d811161135a575b61134c8183612a76565b81019061368d565b87611307565b503d611342565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611189565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140561392b565b805f52600a60205260ff600160405f20015460a81c1615610323576114298161375d565b611432816129fa565b6004810361144d5750634a5541ef60e01b5f5260045260245ffd5b611456816129fa565b60038103611471575063fe19f19f60e01b5f5260045260245ffd5b60029061147d816129fa565b14611556576114a0815f52600a6020526001600160a01b0360405f205416331490565b1561153757805f52600a60205260ff60405f205460f01c1615611525576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611643575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161162f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116726128dd565b5f546001600160a01b03811633810361164357506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116e86128dd565b168015611705575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174f6004356136ad565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177c612ea3565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c683612a3d565b825260208201526117ec8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182961392b565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186b913691612d66565b9081519161187883612d4e565b926118866040519485612a76565b808452601f1961189582612d4e565b015f5b818110611a8857505064ffffffffff4216916001600160801b036118bb82613985565b51511667ffffffffffffffff60206118d284613985565b5101511664ffffffffff8060406118e886613985565b5101511686011690604051926118fd84612a21565b83526020830152604082015261191286613985565b5261191c85613985565b5060015b8281106119f45750505061193682600401612e82565b9261194360248401612e82565b9261195060448201612e6e565b916064820135936001600160a01b0385168095036102b0576020966119ec966119ac966001600160801b036119e1976001600160a01b0361199360848a01612e96565b94816119a160a48c01612e96565b976040519d8e612a04565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e03565b6101008201526139a6565b604051908152f35b806001600160801b03611a0960019385613992565b51511667ffffffffffffffff6020611a218487613992565b5101511664ffffffffff806040611a3b5f1987018d613992565b51015116816040611a4c878a613992565b5101511601169060405192611a6084612a21565b835260208301526040820152611a768289613992565b52611a818188613992565b5001611920565b602090611a93612ebb565b82828901015201611898565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad0903690600401612957565b9060243567ffffffffffffffff81116102b057611af1903690600401612957565b9091611afb61392b565b818403611b67575f5b848110611b0d57005b80611b61611b1e6001938886612e4a565b35611b2a838987612e4a565b355f5260036020526001600160a01b0360405f205416611b53611b4e85898b612e4a565b612e6e565b91611b5c61392b565b6133df565b01611b04565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614156565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0a8261375d565b600581101561099257600203611c28575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1b565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8461392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0157611cc3816140e4565b156113ae57805f5260036020526001600160a01b0360405f205416151580611dfa575b80611ddd575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d94575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8257005b637e27328960e01b5f5260045260245ffd5b611db3835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cec565b505f611ce6565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3d3661291d565b9060405192611e4d602085612a76565b5f8452612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec161392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c457611f3c815f52600a6020526001600160a01b0360405f205416331490565b1561153757611f4a816136ce565b90805f52600a602052611f62600260405f2001612ed9565b916001600160801b038351166001600160801b03821610156121ab57815f52600a60205260ff60405f205460f01c161561219857806001600160801b03602081611fb6948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612173575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120a96001600160a01b03600160405f2001541694611232888588614660565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ec57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91612154575b50160361214257005b632187e5e760e21b5f5260045260245ffd5b61216d915060203d60201161135a5761134c8183612a76565b84612139565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612000565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121d76128dd565b6001600160a01b035f54169033820361231657806001600160a01b03913b156122ea57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610603575f916122bb575b501561229057805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122dd915060203d6020116122e3575b6122d58183612a76565b810190612e32565b82612245565b503d6122cb565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236761392b565b6040519061237482612a04565b61238081600401612909565b825261238e60248201612909565b602083015261239f60448201612ab4565b604083015260648101356001600160a01b03811681036102b05760608301526123ca608482016129ed565b60808301526123db60a482016129ed565b60a08301526123ec60c48201612d3c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e16119ec926124306020953690602460048201359101612d66565b60e0840152610104369101612e03565b346102b05760203660031901126102b0576001600160a01b036124616128dd565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248e3661291d565b91612b0a565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e99061375d565b600581101561099257806020911590811561250a575b506040519015158152f35b6001915014826124ff565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125aa575b612578575b506001600160801b0360405191168152f35b6125a49150805f52600a835261259e6001600160801b03600260405f20015416916136ce565b90612aea565b82612566565b50805f52600a835260ff600160405f20015460a01c1615612561565b346102b05760403660031901126102b0576125df6128dd565b6024356125eb816136ad565b331515806126b8575b80612685575b6126595781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fa565b50336001600160a01b03821614156125f4565b346102b05760203660031901126102b057602061174f600435612ac8565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279a575b602083108114610b9557828552908115610b71575060011461273c5761058283610aff81850382612a76565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278057509091508101602001610aff610aef565b919260018160209254838588010152019101909291612768565b91607f1691612710565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612822575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561286d575b811561285c575b508361281b565b6301ffc9a760e01b91501483612855565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061284e565b5f5b8381106128a85750505f910152565b8181015183820152602001612899565b906020916128d181518092818552858086019101612897565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a55750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612998565b359081151582036102b057565b6005111561099257565b610120810190811067ffffffffffffffff821117610fd757604052565b6060810190811067ffffffffffffffff821117610fd757604052565b6040810190811067ffffffffffffffff821117610fd757604052565b610140810190811067ffffffffffffffff821117610fd757604052565b90601f8019910116810190811067ffffffffffffffff821117610fd757604052565b67ffffffffffffffff8111610fd757601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad1816136ad565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162f57565b91906001600160a01b031680156106ef57815f5260036020526001600160a01b0360405f205416151580612d34575b80612d17575b612d04577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c4f575b6001600160a01b03935085612c18575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0057505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c37825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b9f565b9192905080612cad575b15612c6657828291612b8f565b8284612c7e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cdb575b80612c595750825f526005602052336001600160a01b0360405f20541614612c59565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cb8565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b3f565b506001612b39565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd75760051b60200190565b929192612d7282612d4e565b93612d806040519586612a76565b60606020868581520193028201918183116102b057925b828410612da45750505050565b6060848303126102b05760405190612dbb82612a21565b612dc485612ab4565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df360408801612d3c565b6040820152815201930192612d97565b91908260409103126102b057604051612e1b81612a3d565b6020808294612e2981612909565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb082612a3d565b5f6020838281520152565b60405190612ec882612a21565b5f6040838281528260208201520152565b90604051612ee681612a21565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1781612d4e565b92612f256040519485612a76565b81845260208401905f5260205f205f915b838310612f435750505050565b600160208192604051612f5581612a21565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f36565b90612f9e838284612b0a565b803b612fab575b50505050565b602091612ff16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b8565b03815f865af15f9181613061575b5061302d575061300d6141d7565b805190816130285782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361304f57505f808080612fa5565b633250574960e11b5f5260045260245ffd5b61307b91925060203d60201161135a5761134c8183612a76565b905f612fff565b9061308b61392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f205416948583141580613364575b613330576001600160801b0361311786614206565b168085116132fd575061313c90855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561317f90612ed9565b6001600160801b036131a38160208401511692826040818351169201511690612aea565b1611156132cb575b835f52600a6020526131cf836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b5575b6132395750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613296575b50160361214257808080612fa5565b6132af915060203d60201161135a5761134c8183612a76565b5f613287565b50835f52600960205260ff60405f20541661322f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ab565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061336e856140e4565b15613102565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f20541694858314158061367d575b613330576001600160801b0361346c86614206565b168085116132fd575061349190855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d490612ed9565b6001600160801b036134f88160208401511692826040818351169201511690612aea565b16111561364b575b835f52600a602052613524836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613626575b61358e5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613607575b5016036135eb57808080612fa5565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613620915060203d60201161135a5761134c8183612a76565b5f6135dc565b5060ff613644856001600160a01b03165f52600960205260405f2090565b5416613584565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613500565b50613687856140e4565b15613457565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d82575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375757815f52600a60205264ffffffffff60405f205460c81c16111561373c57805f52600b602052600160405f2054115f14613733576137309061430c565b90565b6137309061424c565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f1461377f5750600490565b805f52600a60205260405f205460f81c6137eb57805f52600a60205264ffffffffff60405f205460a01c1642106137e6576137b9816136ce565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e157600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613919575b806138fc575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c5575b16806138ad575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613869565b6138e4835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613862565b50805f52600a60205260ff600160405f20015460b01c1615613816565b506001600160a01b0382161515613810565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361395d57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5a5760200190565b8051821015612e5a5760209160051b010190565b906139c86001600160801b036040840151166020610100850151015190614522565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bc578015614094578151801561406c577f00000000000000000000000000000000000000000000000000000000000000008111614041575064ffffffffff6040613a3684613985565b51015116811015613ffd57505f905f905f81515f905b808210613f75575050505064ffffffffff80421691169081811015613f475750506001600160801b031690818103613f1957505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c218751975f19890190613992565b51015160c81b169360a01b169116171785555f5b818110613e0b575050600187016007556001600160a01b0360208301511680156106ef57613c6b886001600160a01b03926137f1565b16613ddf578682613cb96001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145ff565b6001600160801b0360208401511680613daf575b506001600160a01b0381511694613da4613d866001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2b8b612a3d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612988565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dd9906001600160a01b036060840151166001600160a01b0361010085015151169033906145ff565b5f613ccd565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e268160e0870151613992565b51825468010000000000000000811015610fd75760018101808555811015612e5a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c35565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f99906001600160801b03613f908588613992565b5151169061422c565b9364ffffffffff806040613fad8685613992565b51015116941680851115613fc957506001849301909291613a4c565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400e84613985565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412a575b508115614111575090565b90506001600160a01b036141253392612ac8565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614106565b805f52600a60205261416d600260405f2001612ed9565b90805f52600a60205260ff600160405f20015460a01c165f1461419b5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ba5750613730906136ce565b61373091506001600160801b036040818351169201511690612aea565b3d15614201573d906141e882612a98565b916141f66040519384612a76565b82523d5f602084013e565b606090565b6137309061421381614156565b905f52600a602052600260405f20015460801c90612aea565b906001600160801b03809116911601906001600160801b03821161162f57565b5f818152600a60205260409020546142839064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b0565b90805f52600b60205260405f20805415612e5a575f526142d867ffffffffffffffff60205f205460801c1692825f52600a6020526142d36001600160801b03600260405f20015416948592614790565b614803565b9182136142f557506142f16001600160801b03916148de565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433082612a59565b6101206143c360028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612ed9565b92019182525f52600b6020526143db60405f20612f0b565b915f9264ffffffffff60406143ef83613985565b510151168664ffffffffff5f925b16106144e3578161447464ffffffffff9697988784816001600160801b0361442c6142d3986144799b9a613992565b5151169a8b9867ffffffffffffffff6020614447868b613992565b51015116978260406144598784613992565b5101511694806144c6575050511680925b03169203166146b0565b614790565b91821361449a5750906001600160801b0361449481936148de565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c1575090565b905090565b60409250906144d8915f190190613992565b51015116809261446a565b936001600160801b03600191816144fa8886613992565b51511601169401958064ffffffffff8060406145168b87613992565b510151169892986143fd565b91909160405161453181612a3d565b5f81525f6020820152926001600160801b0382169081156145e25767016345785d8a000081116145ab5761456d6001600160801b0391836154fb565b1660208501918183521115614597576001600160801b03918261459292511690612aea565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f381612a3d565b5f81525f602082015290565b9091926001600160a01b0361465e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614659608483612a76565b614913565b565b61465e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614659606483612a76565b600160ff1b81148015614783575b61475b575f811215614752576146e2815f035b5f84121561474b57835f0390614998565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471c575f19911813156147175790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614998565b6146e2816146d1565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146be565b806147aa57506147a657670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f557806147cd575050670de0b6b3a764000090565b670de0b6b3a764000081146147f1576147ec906142d361373093614a9e565b614bf5565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d1575b6148a9575f8112156148a057614835815f035b5f84121561489957835f03906154fb565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486a575f19911813156147175790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fb565b61483581614824565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614811565b5f81126148e85790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493c93169360208151910182865af16149356141d7565b90836155a9565b805190811515918261497d575b50506149525750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149909250602080918301019101612e32565b155f80614949565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a635781841015614a2957670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a70570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a70576ec097ce7bc90715b34b9f10000000000590565b805f811315614bca57670de0b6b3a76400008112614baa57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9757506706f05b59d3b20000905b5f8213614b615750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b89575b60011d90614b54565b809192019160011d90614b80565b9050670de0b6b3a7640000929150020290565b5f1991508015614a70576ec097ce7bc90715b34b9f100000000005614abb565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c225768033dd1780914b971141981126137e657614c19905f03614bf5565b61373090614a84565b680a688906bd8affffff81136154d057670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539b575b670de0b6b3a76400009066ff000000000000831661528b575b65ff00000000008316615183575b64ff000000008316615083575b63ff0000008316614f8b575b62ff00008316614e9b575b61ff008316614db3575b60ff8316614cd3575b029060401c60bf031c90565b60808316614da0575b60408316614d8d575b60208316614d7a575b60108316614d67575b60088316614d54575b60048316614d41575b60028316614d2e575b6001831615614cc757680100000000000000010260401c614cc7565b680100000000000000010260401c614d12565b680100000000000000030260401c614d09565b680100000000000000060260401c614d00565b6801000000000000000b0260401c614cf7565b680100000000000000160260401c614cee565b6801000000000000002c0260401c614ce5565b680100000000000000590260401c614cdc565b6180008316614e88575b6140008316614e75575b6120008316614e62575b6110008316614e4f575b6108008316614e3c575b6104008316614e29575b6102008316614e16575b610100831615614cbe57680100000000000000b10260401c614cbe565b680100000000000001630260401c614df9565b680100000000000002c60260401c614def565b6801000000000000058c0260401c614de5565b68010000000000000b170260401c614ddb565b6801000000000000162e0260401c614dd1565b68010000000000002c5d0260401c614dc7565b680100000000000058b90260401c614dbd565b628000008316614f78575b624000008316614f65575b622000008316614f52575b621000008316614f3f575b620800008316614f2c575b620400008316614f19575b620200008316614f06575b62010000831615614cb4576801000000000000b1720260401c614cb4565b680100000000000162e40260401c614ee8565b6801000000000002c5c80260401c614edd565b68010000000000058b910260401c614ed2565b680100000000000b17210260401c614ec7565b68010000000000162e430260401c614ebc565b680100000000002c5c860260401c614eb1565b6801000000000058b90c0260401c614ea6565b63800000008316615070575b6340000000831661505d575b6320000000831661504a575b63100000008316615037575b63080000008316615024575b63040000008316615011575b63020000008316614ffe575b6301000000831615614ca95768010000000000b172180260401c614ca9565b6801000000000162e4300260401c614fdf565b68010000000002c5c8600260401c614fd3565b680100000000058b90c00260401c614fc7565b6801000000000b17217f0260401c614fbb565b680100000000162e42ff0260401c614faf565b6801000000002c5c85fe0260401c614fa3565b68010000000058b90bfc0260401c614f97565b6480000000008316615170575b644000000000831661515d575b642000000000831661514a575b6410000000008316615137575b6408000000008316615124575b6404000000008316615111575b64020000000083166150fe575b640100000000831615614c9d57680100000000b17217f80260401c614c9d565b68010000000162e42ff10260401c6150de565b680100000002c5c85fe30260401c6150d1565b6801000000058b90bfce0260401c6150c4565b68010000000b17217fbb0260401c6150b7565b6801000000162e42fff00260401c6150aa565b68010000002c5c8601cc0260401c61509d565b680100000058b90c0b490260401c615090565b658000000000008316615278575b654000000000008316615265575b652000000000008316615252575b65100000000000831661523f575b65080000000000831661522c575b650400000000008316615219575b650200000000008316615206575b65010000000000831615614c90576801000000b1721835510260401c614c90565b680100000162e430e5a20260401c6151e5565b6801000002c5c863b73f0260401c6151d7565b68010000058b90cf1e6e0260401c6151c9565b680100000b1721bcfc9a0260401c6151bb565b68010000162e43f4f8310260401c6151ad565b680100002c5c89d5ec6d0260401c61519f565b6801000058b91b5bc9ae0260401c615191565b66800000000000008316615388575b66400000000000008316615375575b66200000000000008316615362575b6610000000000000831661534f575b6608000000000000831661533c575b66040000000000008316615329575b66020000000000008316615316575b6601000000000000831615614c825768010000b17255775c040260401c614c82565b6801000162e525ee05470260401c6152f4565b68010002c5cc37da94920260401c6152e5565b680100058ba01fb9f96d0260401c6152d6565b6801000b175effdc76ba0260401c6152c7565b680100162f3904051fa10260401c6152b8565b6801002c605e2e8cec500260401c6152a9565b68010058c86da1c09ea20260401c61529a565b67800000000000000082166154b1575b670de0b6b3a764000090674000000000000000831661549e575b672000000000000000831661548b575b6710000000000000008316615478575b6708000000000000008316615465575b6704000000000000008316615452575b670200000000000000831661543f575b670100000000000000831661542c575b9050614c69565b680100b1afa5abcbed610260401c615425565b68010163da9fb33356d80260401c615415565b680102c9a3e778060ee70260401c615405565b6801059b0d31585743ae0260401c6153f5565b68010b5586cf9890f62a0260401c6153e5565b6801172b83c7d517adce0260401c6153d5565b6801306fe0a31b7152df0260401c6153c5565b5077b504f333f9de6484800000000000000000000000000000006153ab565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559857670de0b6b3a7640000821015615568577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e657508051156155be57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562c575b6155f7575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155ef56fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614ac36040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360016007556146da90816103e9823960805181613a2e0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146130a257508063027b67441461308057806306fdde0314612fc5578063081812fc14612fa7578063095ea7b314612ea25780631400ecec14612df15780631c1cdd4c14612d8d5780631e99d56914612d7057806323b872dd14612d59578063303acc8514612d1c578063406887cb14612bad57806340e58ee5146128f5578063425d30dd146128a557806342842e0e1461287c57806342966c68146126b857806344267570146126925780634857501f146126215780634869e12d146125e75780634cc55e111461221a57806353b15727146120ef57806357404b12146120295780636352211e14611ffa5780636d0cee7514611ffa57806370a0823114611f9057806375829def14611f22578063780a82c814611ed65780637cad6cd114611df95780637de6b1db14611cac5780638659c27014611907578063894e9a0d1461161f5780638f69b9931461159f5780639067b6771461155057806395d89b4114611448578063a22cb46514611394578063a80fc07114611343578063ab167ccc146111d2578063ad35efd414611173578063b256456914611123578063b88d4fde14611099578063b8a3be6614611064578063b971302a14611016578063bc2be1be14610fc7578063c156a11d14610bc3578063c87b56dd14610ab8578063d4dbd20b14610a67578063d511609f14610a1c578063d975dfed146109d1578063e985e9c514610978578063ea5ead19146106c5578063eac8f5b814610674578063f590c17614610619578063f851a440146105f45763fdd46d6014610263575f80fd5b346105f05760603660031901126105f05760043561027f6131cf565b90610288613331565b610290613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610595575b61057a576001600160801b0361031c8561426e565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c5761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016135fd565b6001600160801b036103b68160208401511692826040818351169201511690613369565b16111561051a575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610504575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916104ca575b50160361049f57005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104ec915060203d6020116104f2575b6104e481836132f3565b810190613733565b5f610496565b503d6104da565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061059f84613a7e565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105f0575f3660031901126105f05760206001600160a01b035f5416604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105f05760403660031901126105f0576004356106e16131cf565b906106eb8161426e565b6106f3613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb576001600160a01b0383169081156105b8576001600160801b03169081156105a557825f5260036020526001600160a01b0360405f205416938482141580610968575b61057a576001600160801b0361077f8561426e565b168084116105605750835f52600a60205282600260405f20015460801c016001600160801b03811161054c576107de90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526107f5600260405f20016135fd565b6001600160801b036108198160208401511692826040818351169201511690613369565b161115610936575b835f52600a602052610845836001600160a01b03600160405f200154169283614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610920575b6108ab57005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916109015750160361049f57005b61091a915060203d6020116104f2576104e481836132f3565b84610496565b50835f52600960205260ff60405f2054166108a5565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610821565b5061097284613a7e565b1561076a565b346105f05760403660031901126105f0576109916131b9565b6001600160a01b036109a16131cf565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b60209161426e565b6001600160801b0360405191168152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a6020526020600260405f20015460801c604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105f05760203660031901126105f057600435610ad581613753565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f9575f90610b46575b610b4290604051918291602083526020830190613194565b0390f35b503d805f833e610b5681836132f3565b8101906020818303126105f05780519067ffffffffffffffff82116105f057019080601f830112156105f057815191610b8e83613315565b91610b9c60405193846132f3565b838352602084830101116105f057610b4292610bbe9160208085019101613173565b610b2a565b346105f05760403660031901126105f057600435610bdf6131cf565b90610be8613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f5260036020526001600160a01b0360405f20541691823303610fb0576001600160801b03610c328361426e565b1680158015610cc6575b50506001600160a01b03811615610cb357610c5f826001600160a01b03926138ea565b169182610c795750637e27328960e01b5f5260045260245ffd5b808303610c8257005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cce613a24565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c16610f8b578415610f78576105a557825f5260036020526001600160a01b0360405f205416908185141580610f68575b610f4c576001600160801b03610d438561426e565b16808211610f325750835f52600a60205280600260405f20015460801c016001600160801b03811161054c57610da290855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610db9600260405f20016135fd565b6001600160801b03610ddd8160208401511692826040818351169201511690613369565b161115610f00575b835f52600a6020526001600160a01b03600160405f20015416610e09828783614294565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610eea575b15610c3c57604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f91610ecb575b50160361049f5780610c3c565b610ee4915060203d6020116104f2576104e481836132f3565b87610ebe565b50815f52600960205260ff60405f205416610e69565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610de5565b908463287ecaef60e21b5f5260045260245260445260645ffd5b50505063b34359d360e01b5f526004523360245260445260645ffd5b50610f7284613a7e565b15610d2e565b83630ff7ee2d60e31b5f5260045260245ffd5b83634a5541ef60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105f05760203660031901126105f0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105f05760803660031901126105f0576110b26131b9565b6110ba6131cf565b6064359167ffffffffffffffff83116105f057366023840112156105f0578260040135916110e783613315565b926110f560405194856132f3565b80845236602482870101116105f0576020815f9260246111219801838801378501015260443591613643565b005b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576111ab90613856565b60405160058210156111be576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105f0576101403660031901126105f0576111ec613a24565b6111f46135df565b64ffffffffff421680825264ffffffffff61120d61362f565b16611328575b60e43564ffffffffff811681036105f05764ffffffffff9101166040820152600435906001600160a01b038216918281036105f057506024356001600160a01b038116908181036105f057506044356001600160801b038116908181036105f057506064356001600160a01b0381168091036105f05760843591821515928381036105f0575060a43593841515948581036105f05750604051966112b688613250565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105f057604051906112f0826132d7565b61010435906001600160a01b03821682036105f057826113209260209452610124358482015260e0820152613b74565b604051908152f35b64ffffffffff61133661362f565b8201166020830152611213565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105f05760403660031901126105f0576113ad6131b9565b602435908115158092036105f0576001600160a01b031690811561141c57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f0575f3660031901126105f0576040515f6002548060011c90600181168015611546575b6020831081146115325782855290811561150e57506001146114b0575b610b428361149c818503826132f3565b604051918291602083526020830190613194565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114f45750909150810160200161149c61148c565b9192600181602092548385880101520191019092916114dc565b60ff191660208086019190915291151560051b8401909101915061149c905061148c565b634e487b7160e01b5f52602260045260245ffd5b91607f169161146f565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576115d790613856565b6005811015806111be5760028214908115611613575b8115611601575b6020826040519015158152f35b90506111be57600460209114826115f4565b5050600381145f6115ed565b346105f05760203660031901126105f0576004355f6101606040516116438161329d565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e082015282610100820152826101208201526116866135df565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260405f206040516116c1816132ba565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c1615158752611760600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016135fd565b610120830190815261177187613856565b60058110156111be576002146118ff575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff1690511515926040516117f78161329d565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f8552611782565b346105f05760203660031901126105f05760043567ffffffffffffffff81116105f05761193890369060040161321f565b90611941613a24565b5f915b80831061194d57005b6119588382846135bb565b3592611962613a24565b835f52600a60205260ff600160405f20015460a81c1615610f9e57835f52600a60205260ff600160405f20015460a01c165f146119ac5783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611c9a576119e1815f52600a6020526001600160a01b0360405f205416331490565b15611c84576119ef81613774565b90805f52600a602052611a07600260405f20016135fd565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081611a5b948188511603169501511690613369565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611c39575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611b6d6001600160a01b03600160405f2001541694611b45888588614294565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611bbe575b50505050506001019190611944565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f91611c1b575b50160361049f5780808080611baf565b611c33915060203d81116104f2576104e481836132f3565b87611c0b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611aa5565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b346105f05760203660031901126105f057600435611cc8613a24565b805f52600a60205260ff600160405f20015460a81c161561066357611cec81613856565b60058110156111be5760048103611d105750634a5541ef60e01b5f5260045260245ffd5b60038103611d2b575063fe19f19f60e01b5f5260045260245ffd5b600214611de757611d50815f52600a6020526001600160a01b0360405f205416331490565b15611c8457805f52600a60205260ff60405f205460f01c1615611dd5576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105f05760203660031901126105f0576004356001600160a01b0381168091036105f0576001600160a01b035f5416338103611ec0575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161054c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600b602052602064ffffffffff60405f205416604051908152f35b346105f05760203660031901126105f057611f3b6131b9565b5f546001600160a01b038116338103611ec057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105f05760203660031901126105f0576001600160a01b03611fb16131b9565b168015611fce575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105f05760203660031901126105f0576020612018600435613753565b6001600160a01b0360405191168152f35b346105f05760203660031901126105f0576004356120456135df565b50805f52600a60205260ff600160405f20015460a81c161561066357806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926120b584613281565b8352602083015260408201526120ed604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105f0576101603660031901126105f057612109613a24565b60405161211581613250565b61211d6131b9565b81526121276131cf565b6020820152612134613331565b60408201526064356001600160a01b03811681036105f057606082015260843580151581036105f057608082015260a43580151581036105f05760a082015260603660c31901126105f05760405161218b81613281565b60c43564ffffffffff811681036105f057815260e43564ffffffffff811681036105f05760208201526101043564ffffffffff811681036105f057604082015260c08201526040610123193601126105f057604051906121ea826132d7565b61012435906001600160a01b03821682036105f057826113209260209452610144358482015260e0820152613b74565b346105f05760403660031901126105f05760043567ffffffffffffffff81116105f05761224b90369060040161321f565b60243567ffffffffffffffff81116105f05761226b90369060040161321f565b612276939193613a24565b8083036125b8575f5b83811061228857005b6122938185856135bb565b3561229f8286866135bb565b355f5260036020526001600160a01b0360405f205416906122c18385896135bb565b356001600160801b038116908181036105f057506122dd613a24565b815f52600a60205260ff600160405f20015460a81c16156105de57815f52600a60205260ff600160405f20015460a01c166105cb5782156125a557801561259257815f5260036020526001600160a01b0360405f205416928381141580612582575b612568576001600160801b036123548461426e565b1680831161254e5750825f52600a60205281600260405f20015460801c016001600160801b03811161054c576123b390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526123ca600260405f20016135fd565b6001600160801b036123ee8160208401511692826040818351169201511690613369565b16111561251c575b825f52600a6020526001600160a01b03600160405f2001541661241a838383614294565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612506575b61248b575b5050505060010161227f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f9576392b9102b60e01b916001600160e01b0319915f916124e8575b50160361049f5780808061247f565b612500915060203d81116104f2576104e481836132f3565b896124d9565b50835f52600960205260ff60405f20541661247a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556123f6565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061258c83613a7e565b1561233f565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357610a0b602091613af0565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f61265a82613856565b60058110156111be57600203612678575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c1661266b565b346105f0575f3660031901126105f05760206001600160a01b0360085416604051908152f35b346105f05760203660031901126105f0576004356126d4613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c16156128515761271381613a7e565b15611c8457805f5260036020526001600160a01b0360405f20541615158061284a575b8061282d575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f20541680159081156127e4575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506127d257005b637e27328960e01b5f5260045260245ffd5b612803835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561278a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561273c565b505f612736565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105f05761112161288d366131e5565b906040519261289d6020856132f3565b5f8452613643565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105f05760203660031901126105f057600435612911613a24565b805f52600a60205260ff600160405f20015460a81c161561066357805f52600a60205260ff600160405f20015460a01c165f1461295a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611c9a5761298c815f52600a6020526001600160a01b0360405f205416331490565b15611c845761299a81613774565b90805f52600a6020526129b2600260405f20016135fd565b916001600160801b038351166001600160801b0382161015611c7157815f52600a60205260ff60405f205460f01c1615611c5e57806001600160801b03602081612a06948188511603169501511690613369565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612b88575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612af06001600160a01b03600160405f2001541694611b45888588614294565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b3357005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f957630d4af11f60e31b916001600160e01b0319915f916109015750160361049f57005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612a50565b346105f05760203660031901126105f057612bc66131b9565b6001600160a01b035f541690338203612d0557806001600160a01b03913b15612cd957166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f9575f91612caa575b5015612c7f57805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612ccc915060203d602011612cd2575b612cc481836132f3565b8101906135a3565b82612c34565b503d612cba565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105f05760203660031901126105f0576001600160a01b03612d3d6131b9565b165f526009602052602060ff60405f2054166040519015158152f35b346105f057611121612d6a366131e5565b91613389565b346105f0575f3660031901126105f0576020600754604051908152f35b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c161561066357612dc590613856565b60058110156111be578060209115908115612de6575b506040519015158152f35b600191501482612ddb565b346105f05760203660031901126105f057600435805f52600a60205260ff600160405f20015460a81c1615610663576020905f90805f52600a835260ff60405f205460f01c1680612e86575b612e54575b506001600160801b0360405191168152f35b612e809150805f52600a8352612e7a6001600160801b03600260405f2001541691613774565b90613369565b82612e42565b50805f52600a835260ff600160405f20015460a01c1615612e3d565b346105f05760403660031901126105f057612ebb6131b9565b602435612ec781613753565b33151580612f94575b80612f61575b612f355781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612ed6565b50336001600160a01b0382161415612ed0565b346105f05760203660031901126105f0576020612018600435613347565b346105f0575f3660031901126105f0576040515f6001548060011c90600181168015613076575b6020831081146115325782855290811561150e575060011461301857610b428361149c818503826132f3565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061305c5750909150810160200161149c61148c565b919260018160209254838588010152019101909291613044565b91607f1691612fec565b346105f0575f3660031901126105f057602060405167016345785d8a00008152f35b346105f05760203660031901126105f057600435906001600160e01b031982168092036105f057817f4906490600000000000000000000000000000000000000000000000000000000602093149081156130fe575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613149575b8115613138575b50836130f7565b6301ffc9a760e01b91501483613131565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061312a565b5f5b8381106131845750505f910152565b8181015183820152602001613175565b906020916131ad81518092818552858086019101613173565b601f01601f1916010190565b600435906001600160a01b03821682036105f057565b602435906001600160a01b03821682036105f057565b60609060031901126105f0576004356001600160a01b03811681036105f057906024356001600160a01b03811681036105f0579060443590565b9181601f840112156105f05782359167ffffffffffffffff83116105f0576020808501948460051b0101116105f057565b610100810190811067ffffffffffffffff82111761326d57604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761326d57604052565b610180810190811067ffffffffffffffff82111761326d57604052565b610140810190811067ffffffffffffffff82111761326d57604052565b6040810190811067ffffffffffffffff82111761326d57604052565b90601f8019910116810190811067ffffffffffffffff82111761326d57604052565b67ffffffffffffffff811161326d57601f01601f191660200190565b604435906001600160801b03821682036105f057565b61335081613753565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161054c57565b91906001600160a01b03168015610cb357815f5260036020526001600160a01b0360405f20541615158061359b575b8061357e575b61356b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836134b6575b6001600160a01b0393508561347f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8257505050565b61349e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f19815401905561341e565b9192905080613514575b156134cd5782829161340e565b82846134e557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613542575b806134c05750825f526005602052336001600160a01b0360405f205416146134c0565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541661351f565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156133be565b5060016133b8565b908160209103126105f0575180151581036105f05790565b91908110156135cb5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b604051906135ec82613281565b5f6040838281528260208201520152565b9060405161360a81613281565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105f05790565b9061364f838284613389565b803b61365c575b50505050565b6020916136a26001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613194565b03815f865af15f9181613712575b506136de57506136be61423f565b805190816136d95782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361370057505f808080613656565b633250574960e11b5f5260045260245ffd5b61372c91925060203d6020116104f2576104e481836132f3565b905f6136b0565b908160209103126105f057516001600160e01b0319811681036105f05790565b805f5260036020526001600160a01b0360405f2054169081156127d2575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c16904210801561384c575b61384657815f52600a60205264ffffffffff60405f205460c81c16908142101561382957806137db9203904203614422565b815f52600a6020526137fe6001600160801b03600260405f20015416809261450e565b908111613813576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b50428110156137a9565b805f52600a60205260ff600160405f20015460a01c165f146138785750600490565b805f52600a60205260405f205460f81c6138e457805f52600a60205264ffffffffff60405f205460a01c1642106138df576138b281613774565b905f52600a6020526001600160801b0380600260405f200154169116105f146138da57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613a12575b806139f5575b61281b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836139be575b16806139a6575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613962565b6139dd835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561395b565b50805f52600a60205260ff600160405f20015460b01c161561390f565b506001600160a01b0382161515613909565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613a5657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613ac4575b508115613aab575090565b90506001600160a01b03613abf3392613347565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613aa0565b805f52600a602052613b07600260405f20016135fd565b90805f52600a60205260ff600160405f20015460a01c165f14613b355750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613b575750613b5490613774565b90565b613b5491506001600160801b036040818351169201511690613369565b90613b956001600160801b03604084015116602060e08501510151906142eb565b916001600160801b0383511660c082015190156142175764ffffffffff815116156141ef576020810164ffffffffff81511680614163575b5050604064ffffffffff82511691019064ffffffffff825116908181101561413557505064ffffffffff80421691511690818110156141075750506007549280516001600160801b03169160405192613c2584613281565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613c8b896132ba565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613f0b91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff16806140e7575b50600185016007556001600160a01b036020820151168015610cb357613f79866001600160a01b03926138ea565b166140bb57613fa46001600160a01b036060830151166001600160801b0384511690309033906143c8565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061408c575b506140836001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b6140b5906001600160a01b036060880151166001600160a01b0360e089015151169033906143c8565b5f613fdf565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613f4b565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff835116818110156141c157505064ffffffffff90511664ffffffffff60408301511690818110613bcd577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614269573d9061425082613315565b9161425e60405193846132f3565b82523d5f602084013e565b606090565b613b549061427b81613af0565b905f52600a602052600260405f20015460801c90613369565b6142e9926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526142e46064836132f3565b6145bc565b565b9190916040516142fa816132d7565b5f81525f6020820152926001600160801b0382169081156143ab5767016345785d8a00008111614374576143366001600160801b03918361450e565b1660208501918183521115614360576001600160801b03918261435b92511690613369565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516143bc816132d7565b5f81525f602082015290565b9091926001600160a01b036142e99481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526142e46084836132f3565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146144ed57818410156144b357670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156144fa570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f19838209838202918280831092039180830392146145ab57670de0b6b3a764000082101561457b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b036145e593169360208151910182865af16145de61423f565b9083614641565b8051908115159182614626575b50506145fb5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61463992506020809183010191016135a3565b155f806145f2565b9061467e575080511561465657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806146c4575b61468f575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561468756fea164736f6c634300081a000a"; + hex"60a0604052346103bf57614b706040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478790816103e9823960805181613adb0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313757508063027b67441461311557806306fdde031461305a578063081812fc1461303c578063095ea7b314612f375780631400ecec14612e865780631c1cdd4c14612e225780631e99d56914612e0557806323b872dd14612dee578063303acc8514612db1578063406887cb14612c4257806340e58ee51461296b578063425d30dd1461291b57806342842e0e146128f257806342966c681461272e57806344267570146127085780634857501f146126975780634869e12d1461265d5780634cc55e11146122b657806353b157271461218b57806357404b12146120c55780636352211e146120965780636d0cee751461209657806370a082311461202c57806375829def14611fbe578063780a82c814611f725780637cad6cd114611e955780637de6b1db14611d485780638659c27014611991578063894e9a0d146116a95780638f69b993146116295780639067b677146115da57806395d89b41146114d2578063a22cb4651461141e578063a80fc071146113cd578063ab167ccc1461125c578063ad35efd4146111fd578063b2564569146111ad578063b88d4fde14611123578063b8a3be66146110ee578063b971302a146110a0578063bc2be1be14611051578063c156a11d14610c3c578063c87b56dd14610b31578063d4dbd20b14610ae0578063d511609f14610a95578063d975dfed14610a4a578063e985e9c5146109f1578063ea5ead19146106ac578063eac8f5b81461065b578063f590c17614610600578063f851a440146105db5763fdd46d6014610263575f80fd5b346105d75760603660031901126105d75760043561027f613264565b906102886133c6565b610290613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431b565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136aa565b6001600160801b036103b681602084015116928260408183511692015116906133fe565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b632187e5e760e21b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb8183613388565b8101906137e0565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061058684613b2b565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d7575f3660031901126105d75760206001600160a01b035f5416604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d75760403660031901126105d7576004356106c8613264565b906106d28161431b565b906106db613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c166109df576001600160a01b0383169182156109cc576001600160801b03169182156109b957815f5260036020526001600160a01b0360405f2054169384821415806109a9575b61098e576001600160801b036107678461431b565b168085116109745750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107dd600260405f20016136aa565b6001600160801b0361080181602084015116928260408183511692015116906133fe565b161115610942575b825f52600a60205261082d846001600160a01b03600160405f200154169283614341565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092c575b61089d575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090d575b5016036108fa578180610892565b50632187e5e760e21b5f5260045260245ffd5b610926915060203d6020116104d9576104cb8183613388565b856108ec565b50835f52600960205260ff60405f20541661088d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610809565b848463287ecaef60e21b5f5260045260245260445260645ffd5b509063b34359d360e01b5f526004523360245260445260645ffd5b506109b383613b2b565b15610752565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105d75760403660031901126105d757610a0a61324e565b6001600160a01b03610a1a613264565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a8460209161431b565b6001600160801b0360405191168152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a6020526020600260405f20015460801c604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d75760203660031901126105d757600435610b4e81613800565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bbf575b610bbb90604051918291602083526020830190613229565b0390f35b503d805f833e610bcf8183613388565b8101906020818303126105d75780519067ffffffffffffffff82116105d757019080601f830112156105d757815191610c07836133aa565b91610c156040519384613388565b838352602084830101116105d757610bbb92610c379160208085019101613208565b610ba3565b346105d75760403660031901126105d757600435610c58613264565b610c60613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103a576001600160801b03610caa8461431b565b169081158015610d33575b506001600160a01b03811615610d2057610cd7846001600160a01b0392613997565b169182610cf15783637e27328960e01b5f5260045260245ffd5b8084918403610d0557602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3b613ad1565b845f52600a60205260ff600160405f20015460a81c161561102857845f52600a60205260ff600160405f20015460a01c1661101557831561100257610fef57835f5260036020526001600160a01b0360405f2054168084141580610fdf575b610fc4576001600160801b03610daf8661431b565b16808411610faa5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e0e90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e25600260405f20016136aa565b6001600160801b03610e4981602084015116928260408183511692015116906133fe565b161115610f78575b845f52600a6020526001600160a01b03600160405f20015416610e75848683614341565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f62575b15610cb5576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f43575b501614610cb557632187e5e760e21b5f5260045260245ffd5b610f5c915060203d6020116104d9576104cb8183613388565b88610f2a565b50805f52600960205260ff60405f205416610ed5565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e51565b838663287ecaef60e21b5f5260045260245260445260645ffd5b838563b34359d360e01b5f526004523360245260445260645ffd5b50610fe985613b2b565b15610d9a565b8363d2aabcd960e01b5f5260045260245ffd5b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d75760203660031901126105d7576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d75760803660031901126105d75761113c61324e565b611144613264565b6064359167ffffffffffffffff83116105d757366023840112156105d757826004013591611171836133aa565b9261117f6040519485613388565b80845236602482870101116105d7576020815f9260246111ab98018388013785010152604435916136f0565b005b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761123590613903565b6040516005821015611248576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d7576101403660031901126105d757611276613ad1565b61127e61368c565b64ffffffffff421680825264ffffffffff6112976136dc565b166113b2575b60e43564ffffffffff811681036105d75764ffffffffff9101166040820152600435906001600160a01b038216918281036105d757506024356001600160a01b038116908181036105d757506044356001600160801b038116908181036105d757506064356001600160a01b0381168091036105d75760843591821515928381036105d7575060a43593841515948581036105d7575060405196611340886132e5565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d7576040519061137a8261336c565b61010435906001600160a01b03821682036105d757826113aa9260209452610124358482015260e0820152613c21565b604051908152f35b64ffffffffff6113c06136dc565b820116602083015261129d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d75760403660031901126105d75761143761324e565b602435908115158092036105d7576001600160a01b03169081156114a657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7575f3660031901126105d7576040515f6002548060011c906001811680156115d0575b6020831081146115bc57828552908115611598575060011461153a575b610bbb8361152681850382613388565b604051918291602083526020830190613229565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061157e57509091508101602001611526611516565b919260018160209254838588010152019101909291611566565b60ff191660208086019190915291151560051b840190910191506115269050611516565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114f9565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761166190613903565b600581101580611248576002821490811561169d575b811561168b575b6020826040519015158152f35b9050611248576004602091148261167e565b5050600381145f611677565b346105d75760203660031901126105d7576004355f6101606040516116cd81613332565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261171061368c565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260405f2060405161174b8161334f565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ea600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136aa565b61012083019081526117fb87613903565b600581101561124857600214611989575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188181613332565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180c565b346105d75760203660031901126105d75760043567ffffffffffffffff81116105d7576119c29036906004016132b4565b906119cb613ad1565b5f915b8083106119d757005b6119e2838284613668565b35926119ec613ad1565b835f52600a60205260ff600160405f20015460a81c1615611d3657835f52600a60205260ff600160405f20015460a01c165f14611a365783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2457611a6b815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57611a7981613821565b90805f52600a602052611a91600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081611ae59481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc3575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bf76001600160a01b03600160405f2001541694611bcf888588614341565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c48575b505050505060010191906119ce565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca5575b50160361049f5780808080611c39565b611cbd915060203d81116104d9576104cb8183613388565b87611c95565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b2f565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435611d64613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57611d8881613903565b60058110156112485760048103611dac5750634a5541ef60e01b5f5260045260245ffd5b60038103611dc7575063fe19f19f60e01b5f5260045260245ffd5b600214611e8357611dec815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57805f52600a60205260ff60405f205460f01c1615611e71576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d75760203660031901126105d7576004356001600160a01b0381168091036105d7576001600160a01b035f5416338103611f5c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d75760203660031901126105d757611fd761324e565b5f546001600160a01b038116338103611f5c57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d75760203660031901126105d7576001600160a01b0361204d61324e565b16801561206a575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d75760203660031901126105d75760206120b4600435613800565b6001600160a01b0360405191168152f35b346105d75760203660031901126105d7576004356120e161368c565b50805f52600a60205260ff600160405f20015460a81c161561064a57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261215184613316565b835260208301526040820152612189604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d7576101603660031901126105d7576121a5613ad1565b6040516121b1816132e5565b6121b961324e565b81526121c3613264565b60208201526121d06133c6565b60408201526064356001600160a01b03811681036105d757606082015260843580151581036105d757608082015260a43580151581036105d75760a082015260603660c31901126105d75760405161222781613316565b60c43564ffffffffff811681036105d757815260e43564ffffffffff811681036105d75760208201526101043564ffffffffff811681036105d757604082015260c08201526040610123193601126105d757604051906122868261336c565b61012435906001600160a01b03821682036105d757826113aa9260209452610144358482015260e0820152613c21565b346105d75760403660031901126105d75760043567ffffffffffffffff81116105d7576122e79036906004016132b4565b60243567ffffffffffffffff81116105d7576123079036906004016132b4565b612312939193613ad1565b80830361262e575f5b83811061232457005b61232f818585613668565b3561233b828686613668565b355f5260036020526001600160a01b0360405f2054169061235d838589613668565b356001600160801b038116908181036105d75750612379613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109cc5780156109b957815f5260036020526001600160a01b0360405f20541692838114158061261e575b612604576001600160801b036123f08461431b565b168083116125ea5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761244f90845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052612466600260405f20016136aa565b6001600160801b0361248a81602084015116928260408183511692015116906133fe565b1611156125b8575b825f52600a6020526001600160a01b03600160405f200154166124b6838383614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a2575b612527575b5050505060010161231b565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612584575b50160361049f5780808061251b565b61259c915060203d81116104d9576104cb8183613388565b89612575565b50835f52600960205260ff60405f205416612516565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612492565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061262883613b2b565b156123db565b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a84602091613b9d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f6126d082613903565b6005811015611248576002036126ee575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e1565b346105d7575f3660031901126105d75760206001600160a01b0360085416604051908152f35b346105d75760203660031901126105d75760043561274a613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c16156128c75761278981613b2b565b15611d0e57805f5260036020526001600160a01b0360405f2054161515806128c0575b806128a3575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285a575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284857005b637e27328960e01b5f5260045260245ffd5b612879835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612800565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b2565b505f6127ac565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7576111ab6129033661327a565b9060405192612913602085613388565b5f84526136f0565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d75760203660031901126105d757600435612987613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c165f146129d057634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2457612a02815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57612a1081613821565b90805f52600a602052612a28600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081612a7c9481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c1d575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b666001600160a01b03600160405f2001541694611bcf888588614341565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612ba957005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612bfe5750160361049f57005b612c17915060203d6020116104d9576104cb8183613388565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ac6565b346105d75760203660031901126105d757612c5b61324e565b6001600160a01b035f541690338203612d9a57806001600160a01b03913b15612d6e57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d3f575b5015612d1457805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d61915060203d602011612d67575b612d598183613388565b810190613650565b82612cc9565b503d612d4f565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d7576001600160a01b03612dd261324e565b165f526009602052602060ff60405f2054166040519015158152f35b346105d7576111ab612dff3661327a565b9161341e565b346105d7575f3660031901126105d7576020600754604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57612e5a90613903565b6005811015611248578060209115908115612e7b575b506040519015158152f35b600191501482612e70565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a576020905f90805f52600a835260ff60405f205460f01c1680612f1b575b612ee9575b506001600160801b0360405191168152f35b612f159150805f52600a8352612f0f6001600160801b03600260405f2001541691613821565b906133fe565b82612ed7565b50805f52600a835260ff600160405f20015460a01c1615612ed2565b346105d75760403660031901126105d757612f5061324e565b602435612f5c81613800565b33151580613029575b80612ff6575b612fca5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6b565b50336001600160a01b0382161415612f65565b346105d75760203660031901126105d75760206120b46004356133dc565b346105d7575f3660031901126105d7576040515f6001548060011c9060018116801561310b575b6020831081146115bc5782855290811561159857506001146130ad57610bbb8361152681850382613388565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f157509091508101602001611526611516565b9192600181602092548385880101520191019092916130d9565b91607f1691613081565b346105d7575f3660031901126105d757602060405167016345785d8a00008152f35b346105d75760203660031901126105d757600435906001600160e01b031982168092036105d757817f490649060000000000000000000000000000000000000000000000000000000060209314908115613193575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131de575b81156131cd575b508361318c565b6301ffc9a760e01b915014836131c6565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131bf565b5f5b8381106132195750505f910152565b818101518382015260200161320a565b9060209161324281518092818552858086019101613208565b601f01601f1916010190565b600435906001600160a01b03821682036105d757565b602435906001600160a01b03821682036105d757565b60609060031901126105d7576004356001600160a01b03811681036105d757906024356001600160a01b03811681036105d7579060443590565b9181601f840112156105d75782359167ffffffffffffffff83116105d7576020808501948460051b0101116105d757565b610100810190811067ffffffffffffffff82111761330257604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330257604052565b610180810190811067ffffffffffffffff82111761330257604052565b610140810190811067ffffffffffffffff82111761330257604052565b6040810190811067ffffffffffffffff82111761330257604052565b90601f8019910116810190811067ffffffffffffffff82111761330257604052565b67ffffffffffffffff811161330257601f01601f191660200190565b604435906001600160801b03821682036105d757565b6133e581613800565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2057815f5260036020526001600160a01b0360405f205416151580613648575b8061362b575b613618577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613563575b6001600160a01b0393508561352c575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351457505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354b825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b3565b91929050806135c1575b1561357a578282916134a3565b828461359257637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135ef575b8061356d5750825f526005602052336001600160a01b0360405f2054161461356d565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135cc565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613453565b50600161344d565b908160209103126105d7575180151581036105d75790565b91908110156136785760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369982613316565b5f6040838281528260208201520152565b906040516136b781613316565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d75790565b906136fc83828461341e565b803b613709575b50505050565b60209161374f6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613229565b03815f865af15f91816137bf575b5061378b575061376b6142ec565b805190816137865782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137ad57505f808080613703565b633250574960e11b5f5260045260245ffd5b6137d991925060203d6020116104d9576104cb8183613388565b905f61375d565b908160209103126105d757516001600160e01b0319811681036105d75790565b805f5260036020526001600160a01b0360405f205416908115612848575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138f9575b6138f357815f52600a60205264ffffffffff60405f205460c81c1690814210156138d6578061388892039042036144cf565b815f52600a6020526138ab6001600160801b03600260405f2001541680926145bb565b9081116138c0576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b5042811015613856565b805f52600a60205260ff600160405f20015460a01c165f146139255750600490565b805f52600a60205260405f205460f81c61399157805f52600a60205264ffffffffff60405f205460a01c16421061398c5761395f81613821565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398757600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613abf575b80613aa2575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6b575b1680613a53575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a0f565b613a8a835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a08565b50805f52600a60205260ff600160405f20015460b01c16156139bc565b506001600160a01b03821615156139b6565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b71575b508115613b58575090565b90506001600160a01b03613b6c33926133dc565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b4d565b805f52600a602052613bb4600260405f20016136aa565b90805f52600a60205260ff600160405f20015460a01c165f14613be25750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c045750613c0190613821565b90565b613c0191506001600160801b0360408183511692015116906133fe565b90613c426001600160801b03604084015116602060e0850151015190614398565b916001600160801b0383511660c082015190156142c45764ffffffffff8151161561429c576020810164ffffffffff81511680614210575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e257505064ffffffffff80421691511690818110156141b45750506007549280516001600160801b03169160405192613cd284613316565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d388961334f565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fb891906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614194575b50600185016007556001600160a01b036020820151168015610d2057614026866001600160a01b0392613997565b16614168576140516001600160a01b036060830151166001600160801b038451169030903390614475565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614139575b506141306001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614162906001600160a01b036060880151166001600160a01b0360e08901515116903390614475565b5f61408c565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ff8565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561426e57505064ffffffffff90511664ffffffffff60408301511690818110613c7a577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614316573d906142fd826133aa565b9161430b6040519384613388565b82523d5f602084013e565b606090565b613c019061432881613b9d565b905f52600a602052600260405f20015460801c906133fe565b614396926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614391606483613388565b614669565b565b9190916040516143a78161336c565b5f81525f6020820152926001600160801b0382169081156144585767016345785d8a00008111614421576143e36001600160801b0391836145bb565b166020850191818352111561440d576001600160801b039182614408925116906133fe565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144698161336c565b5f81525f602082015290565b9091926001600160a01b036143969481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614391608483613388565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459a578184101561456057670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145a7570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465857670de0b6b3a7640000821015614628577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469293169360208151910182865af161468b6142ec565b90836146ee565b80519081151591826146d3575b50506146a85750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146e69250602080918301019101613650565b155f8061469f565b9061472b575080511561470357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614771575b61473c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473456fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e457614da56060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614997908161040e823960805181613da9015260a051818181612f300152613e520152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461329c57508063027b67441461327a57806306fdde03146131bf578063081812fc146131a1578063095ea7b31461309c5780631400ecec14612feb5780631c1cdd4c14612f875780631e99d56914612f6a57806323b872dd14612f535780632fe4304114612f19578063303acc8514612edc57806332fbe22b14612d7f578063406887cb14612c1057806340e58ee514612958578063425d30dd1461290857806342842e0e146128df57806342966c681461271b57806344267570146126f55780634857501f146126845780634869e12d1461264a5780634cc55e111461229157806357404b12146122035780636352211e146121d45780636d0cee75146121d457806370a082311461216a57806375829def146120fc5780637cad6cd11461200b5780637de6b1db14611ebe5780637f5799f914611e655780638659c27014611aae578063894e9a0d1461176f578063897f362b146114a45780638f69b993146114245780639067b677146113d557806395d89b41146112cd578063a22cb46514611219578063a80fc071146111c8578063ad35efd414611169578063b256456914611119578063b88d4fde1461108f578063b8a3be661461105a578063b971302a1461100c578063bc2be1be14610fbd578063c156a11d14610bc9578063c87b56dd14610abe578063d4dbd20b14610a6d578063d511609f14610a22578063d975dfed146109d7578063e985e9c51461097e578063ea5ead19146106a9578063eac8f5b814610658578063f590c176146105fd578063f851a440146105d85763fdd46d601461026e575f80fd5b346105d45760603660031901126105d45760043561028a6133c9565b90604435916001600160801b038316908184036105d4576102a9613d9f565b825f52600a60205260ff600160405f20015460a81c16156105c257825f52600a60205260ff600160405f20015460a01c166105af576001600160a01b03811690811561059c57821561058957835f5260036020526001600160a01b0360405f205416948583141580610579575b61055e576001600160801b0361032b866145f7565b16808511610544575061035090855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a90613945565b6001600160801b036103ae81602084015116928260408183511692015116906135a0565b161115610512575b835f52600a6020526103da836001600160a01b03600160405f20015416928361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104fc575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916104c2575b50160361049757005b7f861f979c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6104e4915060203d6020116104ea575b6104dc818361352c565b810190613a88565b5f61048e565b503d6104d2565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b50610583856144d2565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d4575f3660031901126105d45760206001600160a01b035f5416604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d45760403660031901126105d4576004356106c56133c9565b906106cf816145f7565b916106d8613d9f565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959576001600160a01b0381168015610946576001600160801b03841691821561058957835f5260036020526001600160a01b0360405f205416948583141580610936575b61055e576001600160801b03610764866145f7565b16808511610544575061078990855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107c390613945565b6001600160801b036107e781602084015116928260408183511692015116906135a0565b161115610904575b835f52600a602052610813836001600160a01b03600160405f20015416928361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806108ee575b61087957005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f916108cf5750160361049757005b6108e8915060203d6020116104ea576104dc818361352c565b8461048e565b50835f52600960205260ff60405f205416610873565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107ef565b50610940856144d2565b1561074f565b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105d45760403660031901126105d4576109976133b3565b6001600160a01b036109a76133c9565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a116020916145f7565b6001600160801b0360405191168152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a6020526020600260405f20015460801c604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d45760203660031901126105d457600435610adb81613aa8565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104f1575f90610b4c575b610b489060405191829160208352602083019061338e565b0390f35b503d805f833e610b5c818361352c565b8101906020818303126105d45780519067ffffffffffffffff82116105d457019080601f830112156105d457815191610b948361354e565b91610ba2604051938461352c565b838352602084830101116105d457610b4892610bc4916020808501910161336d565b610b30565b346105d45760403660031901126105d457600435610be56133c9565b90610bee613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f5260036020526001600160a01b0360405f20541691823303610fa657610c30826145f7565b6001600160801b03811680158015610cce575b5050506001600160a01b03811615610cbb57610c67826001600160a01b0392613c65565b169182610c815750637e27328960e01b5f5260045260245ffd5b808303610c8a57005b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610cd6613d9f565b845f52600a60205260ff600160405f20015460a81c1615610f9457845f52600a60205260ff600160405f20015460a01c16610f81578515610f6e5761058957835f5260036020526001600160a01b0360405f205416918286141580610f5e575b610f43576001600160801b03610d4b866145f7565b16808311610f295750610d7090855f52600a602052600260405f20015460801c61461d565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610daa90613945565b6001600160801b03610dce81602084015116928260408183511692015116906135a0565b161115610ef7575b835f52600a6020526001600160a01b03600160405f20015416610dfa82878361477b565b85857f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051868152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a18133141580610ee1575b610e65575b80610c43565b604051906392b9102b60e01b825284600483015233602483015285604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91610ec2575b5016036104975780610e5f565b610edb915060203d6020116104ea576104dc818361352c565b87610eb5565b50815f52600960205260ff60405f205416610e5a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610dd6565b828663287ecaef60e21b5f5260045260245260445260645ffd5b858563b34359d360e01b5f526004523360245260445260645ffd5b50610f68856144d2565b15610d36565b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b5063216caf0d60e01b5f526004523360245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d45760203660031901126105d4576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d45760803660031901126105d4576110a86133b3565b6110b06133c9565b6064359167ffffffffffffffff83116105d457366023840112156105d4578260040135916110dd8361354e565b926110eb604051948561352c565b80845236602482870101116105d4576020815f9260246111179801838801378501015260443591613998565b005b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576111a190613bd1565b60405160058210156111b4576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d45760403660031901126105d4576112326133b3565b602435908115158092036105d4576001600160a01b03169081156112a157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4575f3660031901126105d4576040515f6002548060011c906001811680156113cb575b6020831081146113b7578285529081156113935750600114611335575b610b48836113218185038261352c565b60405191829160208352602083019061338e565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061137957509091508101602001611321611311565b919260018160209254838588010152019101909291611361565b60ff191660208086019190915291151560051b840190910191506113219050611311565b634e487b7160e01b5f52602260045260245ffd5b91607f16916112f4565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c16156106475761145c90613bd1565b6005811015806111b45760028214908115611498575b8115611486575b6020826040519015158152f35b90506111b45760046020911482611479565b5050600381145f611472565b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d4578036036101206003198201126105d4576114df613d9f565b60c482013590602219018112156105d45781019060048201359167ffffffffffffffff83116105d45760248101908360061b80360383136105d4576004602091611528876137ec565b96611536604051988961352c565b875282870193010101913683116105d457905b8282106117555750505081519161155f836137ec565b9261156d604051948561352c565b808452601f1961157c826137ec565b015f5b81811061173257505064ffffffffff4216916001600160801b036115a282613ac9565b51511664ffffffffff8060206115b785613ac9565b51015116850116604051916115cb836134d7565b825260208201526115db86613ac9565b526115e585613ac9565b5060015b8281106116bd575050506115ff82600401613977565b9261160c60248401613977565b92611619604482016138a5565b916064820135936001600160a01b0385168095036105d4576020966116b596611675966001600160801b036116aa976001600160a01b0361165c60848a0161398b565b948161166a60a48c0161398b565b976040519d8e6134ba565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e436910161383a565b610100820152613df9565b604051908152f35b806001600160801b036116d260019385613ad6565b51511664ffffffffff8060206116eb5f1986018c613ad6565b510151168160206116fc8689613ad6565b5101511601166040519161170f836134d7565b825260208201526117208289613ad6565b5261172b8188613ad6565b50016115e9565b602090604051611741816134d7565b5f81525f838201528282890101520161157f565b60206040916117643685613804565b815201910190611549565b346105d45760203660031901126105d4576004356060610160604051611794816134f3565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f6101208201526040516117da81613510565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611a9a576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b03851687526118d7600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c161515885201613945565b6101208b019081526118e889613bd1565b60058110156111b457600214611a92575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119678c6134f3565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b019889526119bb906138d1565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b489161345e565b5f87526118f9565b634e487b7160e01b5f52604160045260245ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d457611adf90369060040161342d565b90611ae8613d9f565b5f915b808310611af457005b611aff838284613881565b3592611b09613d9f565b835f52600a60205260ff600160405f20015460a81c1615611e5357835f52600a60205260ff600160405f20015460a01c165f14611b535783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611e4157611b88815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57611b9681613aea565b90805f52600a602052611bae600260405f2001613945565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081611c029481885116031695015116906135a0565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611de0575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d146001600160a01b03600160405f2001541694611cec88858861477b565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611d65575b50505050506001019190611aeb565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f91611dc2575b5016036104975780808080611d56565b611dda915060203d81116104ea576104dc818361352c565b87611db2565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611c4c565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600b602052610b48611eaa60405f206138d1565b60405191829160208352602083019061345e565b346105d45760203660031901126105d457600435611eda613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757611efe81613bd1565b60058110156111b45760048103611f225750634a5541ef60e01b5f5260045260245ffd5b60038103611f3d575063fe19f19f60e01b5f5260045260245ffd5b600214611ff957611f62815f52600a6020526001600160a01b0360405f205416331490565b15611e2b57805f52600a60205260ff60405f205460f01c1615611fe7576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d45760203660031901126105d4576004356001600160a01b0381168091036105d4576001600160a01b035f54163381036120e6575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116120d25760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d4576121156133b3565b5f546001600160a01b0381163381036120e657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d45760203660031901126105d4576001600160a01b0361218b6133b3565b1680156121a8575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d45760203660031901126105d45760206121f2600435613aa8565b6001600160a01b0360405191168152f35b346105d45760203660031901126105d45760043561221f6138b9565b50805f52600a60205260ff600160405f20015460a81c1615610647575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c16612269836134d7565b8252602082015261228f8251809264ffffffffff60208092828151168552015116910152565bf35b346105d45760403660031901126105d45760043567ffffffffffffffff81116105d4576122c290369060040161342d565b9060243567ffffffffffffffff81116105d4576122e390369060040161342d565b9190926122ee613d9f565b82810361261a575f5b81811061230057005b61230b818385613881565b35612317828486613881565b355f5260036020526001600160a01b0360405f2054169061234161233c84888a613881565b6138a5565b9161234a613d9f565b815f52600a60205260ff600160405f20015460a81c161561096c57815f52600a60205260ff600160405f20015460a01c16610959578015612607576001600160801b0383169081156125f457825f5260036020526001600160a01b0360405f2054169384821415806125e4575b6125c9576001600160801b036123cc856145f7565b168084116125af57506123f190845f52600a602052600260405f20015460801c61461d565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561242b90613945565b6001600160801b0361244f81602084015116928260408183511692015116906135a0565b16111561257d575b825f52600a6020526001600160a01b03600160405f2001541661247b83838361477b565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612567575b6124ec575b505050506001016122f7565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104f1576392b9102b60e01b916001600160e01b0319915f91612549575b501603610497578080806124e0565b612561915060203d81116104ea576104dc818361352c565b8961253a565b50835f52600960205260ff60405f2054166124db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612457565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506125ee846144d2565b156123b7565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757610a11602091614544565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f6126bd82613bd1565b60058110156111b4576002036126db575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126ce565b346105d4575f3660031901126105d45760206001600160a01b0360085416604051908152f35b346105d45760203660031901126105d457600435612737613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c16156128b457612776816144d2565b15611e2b57805f5260036020526001600160a01b0360405f2054161515806128ad575b80612890575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612847575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061283557005b637e27328960e01b5f5260045260245ffd5b612866835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f1981540190556127ed565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c161561279f565b505f612799565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d4576111176128f0366133f3565b906040519261290060208561352c565b5f8452613998565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d45760203660031901126105d457600435612974613d9f565b805f52600a60205260ff600160405f20015460a81c161561064757805f52600a60205260ff600160405f20015460a01c165f146129bd57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611e41576129ef815f52600a6020526001600160a01b0360405f205416331490565b15611e2b576129fd81613aea565b90805f52600a602052612a15600260405f2001613945565b916001600160801b038351166001600160801b0382161015611e1857815f52600a60205260ff60405f205460f01c1615611e0557806001600160801b03602081612a699481885116031695015116906135a0565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612beb575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b536001600160a01b03600160405f2001541694611cec88858861477b565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612b9657005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104f157630d4af11f60e31b916001600160e01b0319915f916108cf5750160361049757005b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ab3565b346105d45760203660031901126105d457612c296133b3565b6001600160a01b035f541690338203612d6857806001600160a01b03913b15612d3c57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104f1575f91612d0d575b5015612ce257805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d2f915060203d602011612d35575b612d27818361352c565b810190613869565b82612c97565b503d612d1d565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d45760203660031901126105d45760043567ffffffffffffffff81116105d45761014060031982360301126105d457612db9613d9f565b604051612dc5816134ba565b612dd1826004016133df565b8152612ddf602483016133df565b6020820152612df06044830161356a565b604082015260648201356001600160a01b03811681036105d4576060820152612e1b608483016134ad565b6080820152612e2c60a483016134ad565b60a0820152612e3d60c483016137da565b60c082015260e482013567ffffffffffffffff81116105d457820191366023840112156105d457600483013592612e73846137ec565b90612e81604051928361352c565b848252602060048184019660061b83010101903682116105d457602401945b818610612ec25760206116b5866116aa878760e084015261010436910161383a565b6020604091612ed13689613804565b815201950194612ea0565b346105d45760203660031901126105d4576001600160a01b03612efd6133b3565b165f526009602052602060ff60405f2054166040519015158152f35b346105d4575f3660031901126105d45760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105d457611117612f64366133f3565b916135c0565b346105d4575f3660031901126105d4576020600754604051908152f35b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c161561064757612fbf90613bd1565b60058110156111b4578060209115908115612fe0575b506040519015158152f35b600191501482612fd5565b346105d45760203660031901126105d457600435805f52600a60205260ff600160405f20015460a81c1615610647576020905f90805f52600a835260ff60405f205460f01c1680613080575b61304e575b506001600160801b0360405191168152f35b61307a9150805f52600a83526130746001600160801b03600260405f2001541691613aea565b906135a0565b8261303c565b50805f52600a835260ff600160405f20015460a01c1615613037565b346105d45760403660031901126105d4576130b56133b3565b6024356130c181613aa8565b3315158061318e575b8061315b575b61312f5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156130d0565b50336001600160a01b03821614156130ca565b346105d45760203660031901126105d45760206121f260043561357e565b346105d4575f3660031901126105d4576040515f6001548060011c90600181168015613270575b6020831081146113b757828552908115611393575060011461321257610b48836113218185038261352c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061325657509091508101602001611321611311565b91926001816020925483858801015201910190929161323e565b91607f16916131e6565b346105d4575f3660031901126105d457602060405167016345785d8a00008152f35b346105d45760203660031901126105d457600435906001600160e01b031982168092036105d457817f4906490600000000000000000000000000000000000000000000000000000000602093149081156132f8575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613343575b8115613332575b50836132f1565b6301ffc9a760e01b9150148361332b565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613324565b5f5b83811061337e5750505f910152565b818101518382015260200161336f565b906020916133a78151809281855285808601910161336d565b601f01601f1916010190565b600435906001600160a01b03821682036105d457565b602435906001600160a01b03821682036105d457565b35906001600160a01b03821682036105d457565b60609060031901126105d4576004356001600160a01b03811681036105d457906024356001600160a01b03811681036105d4579060443590565b9181601f840112156105d45782359167ffffffffffffffff83116105d4576020808501948460051b0101116105d457565b90602080835192838152019201905f5b81811061347b5750505090565b825180516001600160801b0316855260209081015164ffffffffff16818601526040909401939092019160010161346e565b359081151582036105d457565b610120810190811067ffffffffffffffff821117611a9a57604052565b6040810190811067ffffffffffffffff821117611a9a57604052565b610180810190811067ffffffffffffffff821117611a9a57604052565b6060810190811067ffffffffffffffff821117611a9a57604052565b90601f8019910116810190811067ffffffffffffffff821117611a9a57604052565b67ffffffffffffffff8111611a9a57601f01601f191660200190565b35906001600160801b03821682036105d457565b61358781613aa8565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b0382116120d257565b91906001600160a01b03168015610cbb57815f5260036020526001600160a01b0360405f2054161515806137d2575b806137b5575b6137a2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f205416928233151592836136ed575b6001600160a01b039350856136b6575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303610c8a57505050565b6136d5825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613655565b919290508061374b575b1561370457828291613645565b828461371c57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613779575b806136f75750825f526005602052336001600160a01b0360405f205416146136f7565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613756565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c16156135f5565b5060016135ef565b359064ffffffffff821682036105d457565b67ffffffffffffffff8111611a9a5760051b60200190565b91908260409103126105d45760405161381c816134d7565b602061383581839561382d8161356a565b8552016137da565b910152565b91908260409103126105d457604051613852816134d7565b6020808294613860816133df565b84520135910152565b908160209103126105d4575180151581036105d45790565b91908110156138915760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105d45790565b604051906138c6826134d7565b5f6020838281520152565b9081546138dd816137ec565b926138eb604051948561352c565b81845260208401905f5260205f205f915b8383106139095750505050565b60016020819260405161391b816134d7565b64ffffffffff86546001600160801b038116835260801c16838201528152019201920191906138fc565b9060405161395281613510565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105d45790565b3580151581036105d45790565b906139a48382846135c0565b803b6139b1575b50505050565b6020916139f76001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061338e565b03815f865af15f9181613a67575b50613a335750613a136145c8565b80519081613a2e5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613a5557505f8080806139ab565b633250574960e11b5f5260045260245ffd5b613a8191925060203d6020116104ea576104dc818361352c565b905f613a05565b908160209103126105d457516001600160e01b0319811681036105d45790565b805f5260036020526001600160a01b0360405f205416908115612835575090565b8051156138915760200190565b80518210156138915760209160051b010190565b9064ffffffffff421691805f52600b602052613b0860405f206138d1565b908364ffffffffff6020613b1b85613ac9565b5101511611613bca57805f52600a6020528364ffffffffff60405f205460c81c161115613bab57506001600160801b03613b5482613ac9565b515116916001925b8251841015613ba4578464ffffffffff6020613b788787613ad6565b5101511611613ba4576001600160801b0360019181613b978787613ad6565b5151160116930192613b5c565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613bf35750600490565b805f52600a60205260405f205460f81c613c5f57805f52600a60205264ffffffffff60405f205460a01c164210613c5a57613c2d81613aea565b905f52600a6020526001600160801b0380600260405f200154169116105f14613c5557600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613d8d575b80613d70575b61287e577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613d39575b1680613d21575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613cdd565b613d58835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613cd6565b50805f52600a60205260ff600160405f20015460b01c1615613c8a565b506001600160a01b0382161515613c84565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613dd157565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613e1b6001600160801b03604084015116602061010085015101519061463d565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156144aa578015614482578151801561445a577f0000000000000000000000000000000000000000000000000000000000000000811161442f575064ffffffffff6020613e8984613ac9565b510151168110156143eb57505f905f905f81515f905b808210614363575050505064ffffffffff804216911690818110156143355750506001600160801b03169081810361430757505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff00000000000000000000000000000000000000000000000000602061406b8751975f19890190613ad6565b51015160c81b169360a01b169116171785555f5b818110614255575050600187016007556001600160a01b036020830151168015610cbb576140b5886001600160a01b0392613c65565b166142295786826141036001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b03855116903090339061471a565b6001600160801b03602084015116806141f9575b506001600160a01b03815116946141ee6141d06001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141758b6134d7565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061345e565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b614223906001600160a01b036060840151166001600160a01b03610100850151511690339061471a565b5f614117565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142708160e0870151613ad6565b5182549268010000000000000000841015611a9a5760018401808255841015613891576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161407f565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614387906001600160801b0361437e8588613ad6565b5151169061461d565b9364ffffffffff80602061439b8685613ad6565b510151169416808511156143b757506001849301909291613e9f565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff60206143fc84613ac9565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614518575b5081156144ff575090565b90506001600160a01b03614513339261357e565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6144f4565b805f52600a60205261455b600260405f2001613945565b90805f52600a60205260ff600160405f20015460a01c165f146145895750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6145ab57506145a890613aea565b90565b6145a891506001600160801b0360408183511692015116906135a0565b3d156145f2573d906145d98261354e565b916145e7604051938461352c565b82523d5f602084013e565b606090565b6145a89061460481614544565b905f52600a602052600260405f20015460801c906135a0565b906001600160801b03809116911601906001600160801b0382116120d257565b91909160405161464c816134d7565b5f81525f6020820152926001600160801b0382169081156146fd5767016345785d8a000081116146c6576146886001600160801b039183614850565b16602085019181835211156146b2576001600160801b0391826146ad925116906135a0565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161470e816134d7565b5f81525f602082015290565b9091926001600160a01b036147799481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261477460848361352c565b6147cb565b565b614779926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261477460648361352c565b5f806001600160a01b036147f493169360208151910182865af16147ed6145c8565b90836148fe565b8051908115159182614835575b505061480a5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148489250602080918301019101613869565b155f80614801565b9091905f19838209838202918280831092039180830392146148ed57670de0b6b3a76400008210156148bd577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061493b575080511561491357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614981575b61494c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561494456fea164736f6c634300081a000a"; + hex"60c0604052346103e457614e2e6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a20908161040e823960805181613e32015260a051818181612fa10152613edb0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461330d57508063027b6744146132eb57806306fdde0314613230578063081812fc14613212578063095ea7b31461310d5780631400ecec1461305c5780631c1cdd4c14612ff85780631e99d56914612fdb57806323b872dd14612fc45780632fe4304114612f8a578063303acc8514612f4d57806332fbe22b14612df0578063406887cb14612c8157806340e58ee5146129aa578063425d30dd1461295a57806342842e0e1461293157806342966c681461276d57806344267570146127475780634857501f146126d65780634869e12d1461269c5780634cc55e11146122f657806357404b12146122685780636352211e146122395780636d0cee751461223957806370a08231146121cf57806375829def146121615780637cad6cd1146120705780637de6b1db14611f235780637f5799f914611eca5780638659c27014611b13578063894e9a0d146117d4578063897f362b146115095780638f69b993146114895780639067b6771461143a57806395d89b4114611332578063a22cb4651461127e578063a80fc0711461122d578063ad35efd4146111ce578063b25645691461117e578063b88d4fde146110f4578063b8a3be66146110bf578063b971302a14611071578063bc2be1be14611022578063c156a11d14610c08578063c87b56dd14610afd578063d4dbd20b14610aac578063d511609f14610a61578063d975dfed14610a16578063e985e9c5146109bd578063ea5ead1914610690578063eac8f5b81461063f578063f590c176146105e4578063f851a440146105bf5763fdd46d601461026e575f80fd5b346105bb5760603660031901126105bb5760043561028a61343a565b90604435916001600160801b038316908184036105bb576102a9613e28565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614680565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146a6565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139ce565b6001600160801b036103ae8160208401511692826040818351169201511690613611565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b632187e5e760e21b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c3818361359d565b810190613b11565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b5061056a8561455b565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105bb575f3660031901126105bb5760206001600160a01b035f5416604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bb5760403660031901126105bb576004356106ac61343a565b6106b582614680565b916106be613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c166109ab576001600160a01b0382168015610998576001600160801b03841692831561098557825f5260036020526001600160a01b0360405f205416948583141580610975575b61095a576001600160801b0361074a85614680565b16808611610940575061076f90845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107a9906139ce565b6001600160801b036107cd8160208401511692826040818351169201511690613611565b16111561090e575b825f52600a6020526107f9846001600160a01b03600160405f200154169283614804565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108f8575b610869575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108d9575b5016036108c657818061085e565b50632187e5e760e21b5f5260045260245ffd5b6108f2915060203d6020116104d1576104c3818361359d565b856108b8565b50835f52600960205260ff60405f205416610859565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d5565b858563287ecaef60e21b5f5260045260245260445260645ffd5b828463b34359d360e01b5f526004523360245260445260645ffd5b5061097f8461455b565b15610735565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105bb5760403660031901126105bb576109d6613424565b6001600160a01b036109e661343a565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a50602091614680565b6001600160801b0360405191168152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a6020526020600260405f20015460801c604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bb5760203660031901126105bb57600435610b1a81613b31565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8b575b610b87906040519182916020835260208301906133ff565b0390f35b503d805f833e610b9b818361359d565b8101906020818303126105bb5780519067ffffffffffffffff82116105bb57019080601f830112156105bb57815191610bd3836135bf565b91610be1604051938461359d565b838352602084830101116105bb57610b8792610c0391602080850191016133de565b610b6f565b346105bb5760403660031901126105bb57600435610c2461343a565b610c2c613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f5260036020526001600160a01b0360405f20541690813303610ff957610c6e83614680565b906001600160801b0382169182158015610d02575b50506001600160a01b03811615610cef57610ca6846001600160a01b0392613cee565b169182610cc05783637e27328960e01b5f5260045260245ffd5b8084918403610cd457602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0a613e28565b855f52600a60205260ff600160405f20015460a81c1615610fe757855f52600a60205260ff600160405f20015460a01c16610fd4578415610fc157610fae57845f5260036020526001600160a01b0360405f205416908185141580610f9e575b610f83576001600160801b03610d7f87614680565b16808511610f695750610da490865f52600a602052600260405f20015460801c6146a6565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610dde906139ce565b6001600160801b03610e028160208401511692826040818351169201511690613611565b161115610f37575b845f52600a6020526001600160a01b03600160405f20015416610e2e848683614804565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f21575b610e99575b80610c83565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f02575b501614610e9357632187e5e760e21b5f5260045260245ffd5b610f1b915060203d6020116104d1576104c3818361359d565b88610ee9565b50805f52600960205260ff60405f205416610e8e565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0a565b848763287ecaef60e21b5f5260045260245260445260645ffd5b848663b34359d360e01b5f526004523360245260445260645ffd5b50610fa88661455b565b15610d6a565b8463d2aabcd960e01b5f5260045260245ffd5b85630ff7ee2d60e31b5f5260045260245ffd5b85634a5541ef60e01b5f5260045260245ffd5b8562b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bb5760203660031901126105bb576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bb5760803660031901126105bb5761110d613424565b61111561343a565b6064359167ffffffffffffffff83116105bb57366023840112156105bb57826004013591611142836135bf565b92611150604051948561359d565b80845236602482870101116105bb576020815f92602461117c9801838801378501015260443591613a21565b005b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761120690613c5a565b6040516005821015611219576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bb5760403660031901126105bb57611297613424565b602435908115158092036105bb576001600160a01b031690811561130657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb575f3660031901126105bb576040515f6002548060011c90600181168015611430575b60208310811461141c578285529081156113f8575060011461139a575b610b87836113868185038261359d565b6040519182916020835260208301906133ff565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113de57509091508101602001611386611376565b9192600181602092548385880101520191019092916113c6565b60ff191660208086019190915291151560051b840190910191506113869050611376565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611359565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576114c190613c5a565b60058110158061121957600282149081156114fd575b81156114eb575b6020826040519015158152f35b905061121957600460209114826114de565b5050600381145f6114d7565b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb578036036101206003198201126105bb57611544613e28565b60c482013590602219018112156105bb5781019060048201359167ffffffffffffffff83116105bb5760248101908360061b80360383136105bb57600460209161158d87613875565b9661159b604051988961359d565b875282870193010101913683116105bb57905b8282106117ba575050508151916115c483613875565b926115d2604051948561359d565b808452601f196115e182613875565b015f5b81811061179757505064ffffffffff4216916001600160801b0361160782613b52565b51511664ffffffffff80602061161c85613b52565b510151168501166040519161163083613548565b8252602082015261164086613b52565b5261164a85613b52565b5060015b8281106117225750505061166482600401613a00565b9261167160248401613a00565b9261167e6044820161392e565b916064820135936001600160a01b0385168095036105bb5760209661171a966116da966001600160801b0361170f976001600160a01b036116c160848a01613a14565b94816116cf60a48c01613a14565b976040519d8e61352b565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c3565b610100820152613e82565b604051908152f35b806001600160801b0361173760019385613b5f565b51511664ffffffffff8060206117505f1986018c613b5f565b510151168160206117618689613b5f565b5101511601166040519161177483613548565b825260208201526117858289613b5f565b526117908188613b5f565b500161164e565b6020906040516117a681613548565b5f81525f83820152828289010152016115e4565b60206040916117c9368561388d565b8152019101906115ae565b346105bb5760203660031901126105bb5760043560606101606040516117f981613564565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161183f81613581565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611aff576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b038516875261193c600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139ce565b6101208b0190815261194d89613c5a565b600581101561121957600214611af7575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119cc8c613564565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a209061395a565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b87916134cf565b5f875261195e565b634e487b7160e01b5f52604160045260245ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb57611b4490369060040161349e565b90611b4d613e28565b5f915b808310611b5957005b611b6483828461390a565b3592611b6e613e28565b835f52600a60205260ff600160405f20015460a81c1615611eb857835f52600a60205260ff600160405f20015460a01c165f14611bb85783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611ea657611bed815f52600a6020526001600160a01b0360405f205416331490565b15611e9057611bfb81613b73565b90805f52600a602052611c13600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081611c67948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e45575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d796001600160a01b03600160405f2001541694611d51888588614804565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dca575b50505050506001019190611b50565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e27575b5016036104975780808080611dbb565b611e3f915060203d81116104d1576104c3818361359d565b87611e17565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb1565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600b602052610b87611f0f60405f2061395a565b6040519182916020835260208301906134cf565b346105bb5760203660031901126105bb57600435611f3f613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57611f6381613c5a565b60058110156112195760048103611f875750634a5541ef60e01b5f5260045260245ffd5b60038103611fa2575063fe19f19f60e01b5f5260045260245ffd5b60021461205e57611fc7815f52600a6020526001600160a01b0360405f205416331490565b15611e9057805f52600a60205260ff60405f205460f01c161561204c576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105bb5760203660031901126105bb576004356001600160a01b0381168091036105bb576001600160a01b035f541633810361214b575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121375760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5761217a613424565b5f546001600160a01b03811633810361214b57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bb5760203660031901126105bb576001600160a01b036121f0613424565b16801561220d575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bb5760203660031901126105bb576020612257600435613b31565b6001600160a01b0360405191168152f35b346105bb5760203660031901126105bb57600435612284613942565b50805f52600a60205260ff600160405f20015460a81c161561062e575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122ce83613548565b825260208201526122f48251809264ffffffffff60208092828151168552015116910152565bf35b346105bb5760403660031901126105bb5760043567ffffffffffffffff81116105bb5761232790369060040161349e565b9060243567ffffffffffffffff81116105bb5761234890369060040161349e565b919092612353613e28565b82810361266c575f5b81811061236557005b61237081838561390a565b3561237c82848661390a565b355f5260036020526001600160a01b0360405f205416906123a66123a184888a61390a565b61392e565b916123af613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f52600a60205260ff600160405f20015460a01c16612659578015610998576001600160801b03831690811561098557825f5260036020526001600160a01b0360405f205416938482141580612649575b61262e576001600160801b0361243185614680565b16808411612614575061245690845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612490906139ce565b6001600160801b036124b48160208401511692826040818351169201511690613611565b1611156125e2575b825f52600a6020526001600160a01b03600160405f200154166124e0838383614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125cc575b612551575b5050505060010161235c565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125ae575b50160361049757808080612545565b6125c6915060203d81116104d1576104c3818361359d565b8961259f565b50835f52600960205260ff60405f205416612540565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124bc565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506126538461455b565b1561241c565b50634a5541ef60e01b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a506020916145cd565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f61270f82613c5a565b60058110156112195760020361272d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612720565b346105bb575f3660031901126105bb5760206001600160a01b0360085416604051908152f35b346105bb5760203660031901126105bb57600435612789613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c1615612906576127c88161455b565b15611e9057805f5260036020526001600160a01b0360405f2054161515806128ff575b806128e2575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612899575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288757005b637e27328960e01b5f5260045260245ffd5b6128b8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561283f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f1565b505f6127eb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb5761117c61294236613464565b906040519261295260208561359d565b5f8452613a21565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bb5760203660031901126105bb576004356129c6613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c165f14612a0f57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611ea657612a41815f52600a6020526001600160a01b0360405f205416331490565b15611e9057612a4f81613b73565b90805f52600a602052612a67600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081612abb948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c5c575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612ba56001600160a01b03600160405f2001541694611d51888588614804565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612be857005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c3d5750160361049757005b612c56915060203d6020116104d1576104c3818361359d565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b05565b346105bb5760203660031901126105bb57612c9a613424565b6001600160a01b035f541690338203612dd957806001600160a01b03913b15612dad57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d7e575b5015612d5357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da0915060203d602011612da6575b612d98818361359d565b8101906138f2565b82612d08565b503d612d8e565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb5761014060031982360301126105bb57612e2a613e28565b604051612e368161352b565b612e4282600401613450565b8152612e5060248301613450565b6020820152612e61604483016135db565b604082015260648201356001600160a01b03811681036105bb576060820152612e8c6084830161351e565b6080820152612e9d60a4830161351e565b60a0820152612eae60c48301613863565b60c082015260e482013567ffffffffffffffff81116105bb57820191366023840112156105bb57600483013592612ee484613875565b90612ef2604051928361359d565b848252602060048184019660061b83010101903682116105bb57602401945b818610612f3357602061171a8661170f878760e08401526101043691016138c3565b6020604091612f42368961388d565b815201950194612f11565b346105bb5760203660031901126105bb576001600160a01b03612f6e613424565b165f526009602052602060ff60405f2054166040519015158152f35b346105bb575f3660031901126105bb5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bb5761117c612fd536613464565b91613631565b346105bb575f3660031901126105bb576020600754604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761303090613c5a565b6005811015611219578060209115908115613051575b506040519015158152f35b600191501482613046565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576020905f90805f52600a835260ff60405f205460f01c16806130f1575b6130bf575b506001600160801b0360405191168152f35b6130eb9150805f52600a83526130e56001600160801b03600260405f2001541691613b73565b90613611565b826130ad565b50805f52600a835260ff600160405f20015460a01c16156130a8565b346105bb5760403660031901126105bb57613126613424565b60243561313281613b31565b331515806131ff575b806131cc575b6131a05781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613141565b50336001600160a01b038216141561313b565b346105bb5760203660031901126105bb5760206122576004356135ef565b346105bb575f3660031901126105bb576040515f6001548060011c906001811680156132e1575b60208310811461141c578285529081156113f8575060011461328357610b87836113868185038261359d565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132c757509091508101602001611386611376565b9192600181602092548385880101520191019092916132af565b91607f1691613257565b346105bb575f3660031901126105bb57602060405167016345785d8a00008152f35b346105bb5760203660031901126105bb57600435906001600160e01b031982168092036105bb57817f490649060000000000000000000000000000000000000000000000000000000060209314908115613369575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b4575b81156133a3575b5083613362565b6301ffc9a760e01b9150148361339c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613395565b5f5b8381106133ef5750505f910152565b81810151838201526020016133e0565b90602091613418815180928185528580860191016133de565b601f01601f1916010190565b600435906001600160a01b03821682036105bb57565b602435906001600160a01b03821682036105bb57565b35906001600160a01b03821682036105bb57565b60609060031901126105bb576004356001600160a01b03811681036105bb57906024356001600160a01b03811681036105bb579060443590565b9181601f840112156105bb5782359167ffffffffffffffff83116105bb576020808501948460051b0101116105bb57565b90602080835192838152019201905f5b8181106134ec5750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134df565b359081151582036105bb57565b610120810190811067ffffffffffffffff821117611aff57604052565b6040810190811067ffffffffffffffff821117611aff57604052565b610180810190811067ffffffffffffffff821117611aff57604052565b6060810190811067ffffffffffffffff821117611aff57604052565b90601f8019910116810190811067ffffffffffffffff821117611aff57604052565b67ffffffffffffffff8111611aff57601f01601f191660200190565b35906001600160801b03821682036105bb57565b6135f881613b31565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213757565b91906001600160a01b03168015610cef57815f5260036020526001600160a01b0360405f20541615158061385b575b8061383e575b61382b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613776575b6001600160a01b0393508561373f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61375e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136c6565b91929050806137d4575b1561378d578282916136b6565b82846137a557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613802575b806137805750825f526005602052336001600160a01b0360405f20541614613780565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137df565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613666565b506001613660565b359064ffffffffff821682036105bb57565b67ffffffffffffffff8111611aff5760051b60200190565b91908260409103126105bb576040516138a581613548565b60206138be8183956138b6816135db565b855201613863565b910152565b91908260409103126105bb576040516138db81613548565b60208082946138e981613450565b84520135910152565b908160209103126105bb575180151581036105bb5790565b919081101561391a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bb5790565b6040519061394f82613548565b5f6020838281520152565b90815461396681613875565b92613974604051948561359d565b81845260208401905f5260205f205f915b8383106139925750505050565b6001602081926040516139a481613548565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190613985565b906040516139db81613581565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bb5790565b3580151581036105bb5790565b90613a2d838284613631565b803b613a3a575b50505050565b602091613a806001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906133ff565b03815f865af15f9181613af0575b50613abc5750613a9c614651565b80519081613ab75782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ade57505f808080613a34565b633250574960e11b5f5260045260245ffd5b613b0a91925060203d6020116104d1576104c3818361359d565b905f613a8e565b908160209103126105bb57516001600160e01b0319811681036105bb5790565b805f5260036020526001600160a01b0360405f205416908115612887575090565b80511561391a5760200190565b805182101561391a5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9160405f2061395a565b908364ffffffffff6020613ba485613b52565b5101511611613c5357805f52600a6020528364ffffffffff60405f205460c81c161115613c3457506001600160801b03613bdd82613b52565b515116916001925b8251841015613c2d578464ffffffffff6020613c018787613b5f565b5101511611613c2d576001600160801b0360019181613c208787613b5f565b5151160116930192613be5565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c7c5750600490565b805f52600a60205260405f205460f81c613ce857805f52600a60205264ffffffffff60405f205460a01c164210613ce357613cb681613b73565b905f52600a6020526001600160801b0380600260405f200154169116105f14613cde57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e16575b80613df9575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc2575b1680613daa575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d66565b613de1835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d5f565b50805f52600a60205260ff600160405f20015460b01c1615613d13565b506001600160a01b0382161515613d0d565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5a57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea46001600160801b0360408401511660206101008501510151906146c6565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453357801561450b57815180156144e3577f000000000000000000000000000000000000000000000000000000000000000081116144b8575064ffffffffff6020613f1284613b52565b5101511681101561447457505f905f905f81515f905b8082106143ec575050505064ffffffffff804216911690818110156143be5750506001600160801b03169081810361439057505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f48751975f19890190613b5f565b51015160c81b169360a01b169116171785555f5b8181106142de575050600187016007556001600160a01b036020830151168015610cef5761413e886001600160a01b0392613cee565b166142b257868261418c6001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a3565b6001600160801b0360208401511680614282575b506001600160a01b03815116946142776142596001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141fe8b613548565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134cf565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142ac906001600160a01b036060840151166001600160a01b0361010085015151169033906147a3565b5f6141a0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142f98160e0870151613b5f565b5182549268010000000000000000841015611aff576001840180825584101561391a576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614108565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614410906001600160801b036144078588613b5f565b515116906146a6565b9364ffffffffff8060206144248685613b5f565b5101511694168085111561444057506001849301909291613f28565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448584613b52565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a1575b508115614588575090565b90506001600160a01b0361459c33926135ef565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f61457d565b805f52600a6020526145e4600260405f20016139ce565b90805f52600a60205260ff600160405f20015460a01c165f146146125750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614634575061463190613b73565b90565b61463191506001600160801b036040818351169201511690613611565b3d1561467b573d90614662826135bf565b91614670604051938461359d565b82523d5f602084013e565b606090565b6146319061468d816145cd565b905f52600a602052600260405f20015460801c90613611565b906001600160801b03809116911601906001600160801b03821161213757565b9190916040516146d581613548565b5f81525f6020820152926001600160801b0382169081156147865767016345785d8a0000811161474f576147116001600160801b0391836148d9565b166020850191818352111561473b576001600160801b03918261473692511690613611565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479781613548565b5f81525f602082015290565b9091926001600160a01b036148029481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526147fd60848361359d565b614854565b565b614802926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526147fd60648361359d565b5f806001600160a01b0361487d93169360208151910182865af1614876614651565b9083614987565b80519081151591826148be575b50506148935750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d192506020809183010191016138f2565b155f8061488a565b9091905f198382098382029182808310920391808303921461497657670de0b6b3a7640000821015614946577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c4575080511561499c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0a575b6149d5575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149cd56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615eaf908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a60646105438188066158b3565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906159b4565b60b76106ed5f615ca7565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615ca7565b98601b6028610a1a8c615db2565b610a2384615e2a565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615ca7565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615ca7565b9660b7610ac189615db2565b610aca8b615e2a565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615979565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615979565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615979565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615979565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bf8565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bf8565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c62565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c62565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b916158b3565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615889575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161585e575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615833575b8415615809575b508315615801575b5082156157f9575b5081156157f1575b50156157ea57600101615715565b5050505f90565b90505f6157dc565b91505f6157d4565b92505f6157cc565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6157c4565b7f7a0000000000000000000000000000000000000000000000000000000000000081111593506157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b806158c757506040516156cc602082614713565b600a81101561592d576158d990615408565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b81010301601f198101835282614713565b61593690615408565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b60405190615988604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615be8576159c2615979565b9061271003906127108211614b1157602e60619160506159e461482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a71815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615af882518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b59825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615c1b88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c5182518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c8588945180928580880191016146cd565b830164010714051160dd1b83820152615c5182518093856025850191016146cd565b6004811015614dc75780615cf15750604051615cc4604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d355750604051615d08604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d7757604051615d4a604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d85604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157ea5790600d915f925f925b828410615dd85750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e0c88856156ff565b511614615e22575b820194600101929190615dc5565b859450615e14565b5f90805180156157ea57906010915f925f925b828410615e50575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e8488856156ff565b511614615e9a575b820194600101929190615e3d565b859450615e8c56fea164736f6c634300081a000a"; diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol index 654c2deac..95166bd86 100644 --- a/src/abstracts/SablierV2Lockup.sol +++ b/src/abstracts/SablierV2Lockup.sol @@ -405,8 +405,9 @@ abstract contract SablierV2Lockup is } /// @inheritdoc ISablierV2Lockup - function withdrawMax(uint256 streamId, address to) external override { - withdraw({ streamId: streamId, to: to, amount: _withdrawableAmountOf(streamId) }); + function withdrawMax(uint256 streamId, address to) external override returns (uint128 withdrawnAmount) { + withdrawnAmount = _withdrawableAmountOf(streamId); + withdraw({ streamId: streamId, to: to, amount: withdrawnAmount }); } /// @inheritdoc ISablierV2Lockup @@ -418,6 +419,7 @@ abstract contract SablierV2Lockup is override noDelegateCall notNull(streamId) + returns (uint128 withdrawnAmount) { // Check: the caller is the current recipient. This also checks that the NFT was not burned. address currentRecipient = _ownerOf(streamId); @@ -426,9 +428,9 @@ 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 }); + withdrawnAmount = _withdrawableAmountOf(streamId); + if (withdrawnAmount > 0) { + withdraw({ streamId: streamId, to: currentRecipient, amount: withdrawnAmount }); } // Checks and Effects: transfer the NFT. diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index a192fc8d2..72c6fcf48 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -312,7 +312,8 @@ interface ISablierV2Lockup is /// /// @param streamId The ID of the stream to withdraw from. /// @param to The address receiving the withdrawn assets. - function withdrawMax(uint256 streamId, address to) external; + /// @return withdrawnAmount The amount withdrawn, denoted in units of the asset's decimals. + function withdrawMax(uint256 streamId, address to) external returns (uint128 withdrawnAmount); /// @notice Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the /// NFT to `newRecipient`. @@ -330,7 +331,13 @@ interface ISablierV2Lockup is /// /// @param streamId The ID of the stream NFT to transfer. /// @param newRecipient The address of the new owner of the stream NFT. - function withdrawMaxAndTransfer(uint256 streamId, address newRecipient) external; + /// @return withdrawnAmount The amount withdrawn, denoted in units of the asset's decimals. + function withdrawMaxAndTransfer( + uint256 streamId, + address newRecipient + ) + external + returns (uint128 withdrawnAmount); /// @notice Withdraws assets from streams to the recipient of each stream. /// diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index d9ad43859..98f62a5b4 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -93,17 +93,17 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Get the withdraw amount. - uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); + uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, - amount: withdrawAmount, + amount: expectedWithdrawnAmount, asset: dai }); vm.expectEmit({ emitter: address(lockup) }); @@ -112,11 +112,10 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is emit Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. - lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); + uint128 actualWithdrawnAmount = + lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); // Assert that Alice is the new stream recipient (and NFT owner). diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree index cb45e2a6e..91f754730 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree +++ b/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree @@ -22,4 +22,5 @@ withdrawMaxAndTransfer.t.sol ├── it should transfer the NFT ├── it should emit a {WithdrawFromLockupStream} event ├── it should emit a {Transfer} event - └── it should emit a {MetadataUpdate} event + ├── it should emit a {MetadataUpdate} event + └── it should return the withdrawable amount diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index be7b774bb..e0f6eab91 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -55,31 +55,29 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Get the withdraw amount. - uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); + uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, - amount: withdrawAmount, + amount: expectedWithdrawnAmount, asset: dai }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + uint128 actualWithdrawnAmount = lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + + // Assert that the withdrawn amount has been updated. + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = withdrawAmount; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } } diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.tree b/test/integration/concrete/lockup/withdraw-max/withdrawMax.tree index 46b7d1190..866c7f09f 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.tree +++ b/test/integration/concrete/lockup/withdraw-max/withdrawMax.tree @@ -4,8 +4,10 @@ withdrawMax.t.sol │ ├── it should update the withdrawn amount │ ├── it should mark the stream as depleted │ ├── it should make the stream not cancelable -│ └── it should emit a {WithdrawFromLockupStream} event +│ ├── it should emit a {WithdrawFromLockupStream} event +│ └── it should return the withdrawn amount └── given the end time is in the future ├── it should make the max withdrawal ├── it should update the withdrawn amount - └── it should emit a {WithdrawFromLockupStream} event + ├── it should emit a {WithdrawFromLockupStream} event + └── it should return the withdrawable amount From ec60206db21d0d96282b9b3229d5dbff25c5fe97 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 3 Jul 2024 17:28:53 +0300 Subject: [PATCH 129/132] docs: update OZ and PRB math versions in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c091025f..781609aca 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ forge install --no-commit sablier-labs/v2-core Second, install the project's dependencies: ```shell -forge install --no-commit OpenZeppelin/openzeppelin-contracts@v5.0.0 PaulRBerg/prb-math +forge install --no-commit OpenZeppelin/openzeppelin-contracts@v5.0.2 PaulRBerg/prb-math@v4.0.3 ``` Finally, add these to your `remappings.txt` file: From 7d1b1c48988c32c11dc0a7d147af2cc5257f5dc5 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 3 Jul 2024 17:40:26 +0300 Subject: [PATCH 130/132] chore: remove MAX_SEGMENT_COUNT --- .env.deployment.example | 1 - 1 file changed, 1 deletion(-) diff --git a/.env.deployment.example b/.env.deployment.example index 30200b552..9ba86c60e 100644 --- a/.env.deployment.example +++ b/.env.deployment.example @@ -1,7 +1,6 @@ # Used by the multi-chain deployment script # General -export MAX_SEGMENT_COUNT="THE_MAX_SEGMENT_COUNT" export MNEMONIC="YOUR_MNEMONIC" # RPC URLs From 98121cd38cb0f4fec4e1ad8ef8d2c480eba1fe07 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 3 Jul 2024 14:59:07 +0100 Subject: [PATCH 131/132] docs: roll 1.2.0 (#863) * docs: roll 1.2.0 * docs: remove solidity mention from changelog * docs: update date * docs: update changelog * docs(license): update BUSL license change date * test: update version in BaseScript Test * docs(refactor): use bump * docs(refactor): use bump in OpenZeppelin * docs(refactor): changelog * docs: update changelog * docs: update date in changelog * docs(changelog): address feedback * change date * docs(changelog): include create rename --------- Co-authored-by: andreivladbrg --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ LICENSE.md | 4 ++-- package.json | 2 +- test/utils/BaseScript.t.sol | 2 +- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 649d37279..29020556e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Common Changelog](https://common-changelog.org/). +[1.2.0]: https://github.com/sablier-labs/v2-core/compare/v1.1.2...v1.2.0 [1.1.2]: https://github.com/sablier-labs/v2-core/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/sablier-labs/v2-core/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/sablier-labs/v2-core/compare/v1.0.2...v1.1.0 @@ -11,6 +12,42 @@ The format is based on [Common Changelog](https://common-changelog.org/). [1.0.1]: https://github.com/sablier-labs/v2-core/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/sablier-labs/v2-core/releases/tag/v1.0.0 +## [1.2.0] - 2024-07-03 + +### Changed + +- **Breaking:** move common logic into `Lockup` contract ([#784](https://github.com/sablier-labs/v2-core/pull/784), + [#813](https://github.com/sablier-labs/v2-core/pull/813), [#850](https://github.com/sablier-labs/v2-core/pull/850), + [#941](https://github.com/sablier-labs/v2-core/pull/941)) +- **Breaking:** use a new hook system ([#951](https://github.com/sablier-labs/v2-core/pull/951)) + - Replace `ISablierV2Recipient` with `ISablierLockupRecipient` hook interface + - Remove `try..catch` block from hook calls +- Allow only supported characters in NFT Descriptor asset symbols + ([#945](https://github.com/sablier-labs/v2-core/pull/945), [#960](https://github.com/sablier-labs/v2-core/pull/960), + [#949](https://github.com/sablier-labs/v2-core/pull/949)) +- Bump build dependencies ([#806](https://github.com/sablier-labs/v2-core/pull/806), + [#942](https://github.com/sablier-labs/v2-core/pull/942), [#944](https://github.com/sablier-labs/v2-core/pull/944)) +- Change permissions of `withdraw` function to public ([#785](https://github.com/sablier-labs/v2-core/pull/785)) +- Disallow zero `startTime` ([#813](https://github.com/sablier-labs/v2-core/pull/813), + [#852](https://github.com/sablier-labs/v2-core/pull/852)) +- Rename create functions `createWithTimestamps` and `createWithDurations` across all lockup contracts + ([#798](https://github.com/sablier-labs/v2-core/pull/798)) +- Switch to Bun ([#775](https://github.com/sablier-labs/v2-core/pull/775)) +- Use Solidity v0.8.26 ([#944](https://github.com/sablier-labs/v2-core/pull/944)) + +### Added + +- Add Lockup Tranched contract ([#817](https://github.com/sablier-labs/v2-core/pull/817)) +- Add `precompiles` in the NPM release ([#841](https://github.com/sablier-labs/v2-core/pull/841)) +- Add return value in `withdrawMax` and `withdrawMaxAndTransfer` + ([#961](https://github.com/sablier-labs/v2-core/pull/961)) + +### Removed + +- **Breaking:** remove protocol fee ([#839](https://github.com/sablier-labs/v2-core/pull/839)) +- Remove flash loan abstract contract ([#779](https://github.com/sablier-labs/v2-core/pull/779)) +- Remove `to` from `withdrawMultiple` function ([#785](https://github.com/sablier-labs/v2-core/pull/785)) + ## [1.1.2] - 2023-12-19 ### Changed diff --git a/LICENSE.md b/LICENSE.md index be1df6c0a..f89bb709d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -9,11 +9,11 @@ Parameters Licensor: Sablier Labs Ltd -Licensed Work: Sablier V2 Core The Licensed Work is (C) 2023 Sablier Labs Ltd +Licensed Work: Sablier V2 Core The Licensed Work is (C) 2024 Sablier Labs Ltd Additional Use Grant: Any uses listed and defined at v2-core-license-grants.sablier.eth -Change Date: The earlier of 2027-07-01 or a date specified at v2-core-license-date.sablier.eth +Change Date: The earlier of 2028-07-03 or a date specified at v2-core-license-date.sablier.eth Change License: GNU General Public License v3.0 or later diff --git a/package.json b/package.json index 5dd87be01..c8138bf07 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@sablier/v2-core", "description": "Core smart contracts of the Sablier V2 token distribution protocol", "license": "BUSL-1.1", - "version": "1.1.2", + "version": "1.2.0", "author": { "name": "Sablier Labs Ltd", "url": "https://sablier.com" diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index 21a7d7fc5..764cb1eef 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -17,7 +17,7 @@ contract BaseScript_Test is StdAssertions { function test_ConstructCreate2Salt() public view { string memory chainId = block.chainid.toString(); - string memory version = "1.1.2"; + string memory version = "1.2.0"; string memory salt = string.concat("ChainID ", chainId, ", Version ", version); bytes32 actualSalt = baseScript.constructCreate2Salt(); From 73356945b53e8dd4112f34f3e2c63c278c4a5239 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 4 Jul 2024 16:20:07 +0300 Subject: [PATCH 132/132] docs: update release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29020556e..fb01c70e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ The format is based on [Common Changelog](https://common-changelog.org/). [1.0.1]: https://github.com/sablier-labs/v2-core/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/sablier-labs/v2-core/releases/tag/v1.0.0 -## [1.2.0] - 2024-07-03 +## [1.2.0] - 2024-07-04 ### Changed